* [PATCH 2/3] crypto/qat: add DES capability to Intel QAT driver
From: Arek Kusztal @ 2016-12-02 14:16 UTC (permalink / raw)
To: dev
Cc: fiona.trahe, pablo.de.lara.guarch, john.griffin, deepak.k.jain,
Arek Kusztal
In-Reply-To: <1480688162-27474-1-git-send-email-arkadiuszx.kusztal@intel.com>
This commit adds DES capability to Intel QuickAssist
Technology Driver
Signed-off-by: Arek Kusztal <arkadiuszx.kusztal@intel.com>
---
doc/guides/cryptodevs/qat.rst | 1 +
doc/guides/rel_notes/release_17_02.rst | 6 +++++
drivers/crypto/qat/qat_adf/qat_algs.h | 1 +
drivers/crypto/qat/qat_adf/qat_algs_build_desc.c | 16 +++++++++++++
drivers/crypto/qat/qat_crypto.c | 29 +++++++++++++++++++++++-
5 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/doc/guides/cryptodevs/qat.rst b/doc/guides/cryptodevs/qat.rst
index 607d244..3e97403 100644
--- a/doc/guides/cryptodevs/qat.rst
+++ b/doc/guides/cryptodevs/qat.rst
@@ -54,6 +54,7 @@ Cipher algorithms:
* ``RTE_CRYPTO_CIPHER_AES_GCM``
* ``RTE_CRYPTO_CIPHER_NULL``
* ``RTE_CRYPTO_CIPHER_KASUMI_F8``
+* ``RTE_CRYPTO_CIPHER_DES_CBC``
Hash algorithms:
diff --git a/doc/guides/rel_notes/release_17_02.rst b/doc/guides/rel_notes/release_17_02.rst
index 3b65038..8fd67ab 100644
--- a/doc/guides/rel_notes/release_17_02.rst
+++ b/doc/guides/rel_notes/release_17_02.rst
@@ -38,6 +38,12 @@ New Features
Also, make sure to start the actual text at the margin.
=========================================================
+* **Updated the QAT PMD.**
+
+ The QAT PMD was updated with additional support for:
+
+ * DES algorithm.
+
Resolved Issues
---------------
diff --git a/drivers/crypto/qat/qat_adf/qat_algs.h b/drivers/crypto/qat/qat_adf/qat_algs.h
index dcc0df5..5409e1e 100644
--- a/drivers/crypto/qat/qat_adf/qat_algs.h
+++ b/drivers/crypto/qat/qat_adf/qat_algs.h
@@ -144,4 +144,5 @@ int qat_alg_validate_aes_key(int key_len, enum icp_qat_hw_cipher_algo *alg);
int qat_alg_validate_snow3g_key(int key_len, enum icp_qat_hw_cipher_algo *alg);
int qat_alg_validate_kasumi_key(int key_len, enum icp_qat_hw_cipher_algo *alg);
int qat_alg_validate_3des_key(int key_len, enum icp_qat_hw_cipher_algo *alg);
+int qat_alg_validate_des_key(int key_len, enum icp_qat_hw_cipher_algo *alg);
#endif
diff --git a/drivers/crypto/qat/qat_adf/qat_algs_build_desc.c b/drivers/crypto/qat/qat_adf/qat_algs_build_desc.c
index f4e24b3..fbeef0a 100644
--- a/drivers/crypto/qat/qat_adf/qat_algs_build_desc.c
+++ b/drivers/crypto/qat/qat_adf/qat_algs_build_desc.c
@@ -518,6 +518,10 @@ int qat_alg_aead_session_create_content_desc_cipher(struct qat_session *cdesc,
total_key_size = ICP_QAT_HW_3DES_KEY_SZ;
cipher_cd_ctrl->cipher_state_sz = ICP_QAT_HW_3DES_BLK_SZ >> 3;
proto = ICP_QAT_FW_LA_PROTO_GET(header->serv_specif_flags);
+ } else if (cdesc->qat_cipher_alg == ICP_QAT_HW_CIPHER_ALGO_DES) {
+ total_key_size = ICP_QAT_HW_DES_KEY_SZ;
+ cipher_cd_ctrl->cipher_state_sz = ICP_QAT_HW_DES_BLK_SZ >> 3;
+ proto = ICP_QAT_FW_LA_PROTO_GET(header->serv_specif_flags);
} else {
total_key_size = cipherkeylen;
cipher_cd_ctrl->cipher_state_sz = ICP_QAT_HW_AES_BLK_SZ >> 3;
@@ -858,6 +862,18 @@ int qat_alg_validate_kasumi_key(int key_len, enum icp_qat_hw_cipher_algo *alg)
return 0;
}
+int qat_alg_validate_des_key(int key_len, enum icp_qat_hw_cipher_algo *alg)
+{
+ switch (key_len) {
+ case ICP_QAT_HW_DES_KEY_SZ:
+ *alg = ICP_QAT_HW_CIPHER_ALGO_DES;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
int qat_alg_validate_3des_key(int key_len, enum icp_qat_hw_cipher_algo *alg)
{
switch (key_len) {
diff --git a/drivers/crypto/qat/qat_crypto.c b/drivers/crypto/qat/qat_crypto.c
index 6a6bd2e..4ee1ef8 100644
--- a/drivers/crypto/qat/qat_crypto.c
+++ b/drivers/crypto/qat/qat_crypto.c
@@ -496,6 +496,26 @@ static const struct rte_cryptodev_capabilities qat_pmd_capabilities[] = {
}, }
}, }
},
+ { /* DES CBC */
+ .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+ {.sym = {
+ .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+ {.cipher = {
+ .algo = RTE_CRYPTO_CIPHER_DES_CBC,
+ .block_size = 8,
+ .key_size = {
+ .min = 8,
+ .max = 8,
+ .increment = 0
+ },
+ .iv_size = {
+ .min = 8,
+ .max = 8,
+ .increment = 0
+ }
+ }, }
+ }, }
+ },
RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
};
@@ -637,6 +657,14 @@ qat_crypto_sym_configure_session_cipher(struct rte_cryptodev *dev,
}
session->qat_mode = ICP_QAT_HW_CIPHER_CBC_MODE;
break;
+ case RTE_CRYPTO_CIPHER_DES_CBC:
+ if (qat_alg_validate_des_key(cipher_xform->key.length,
+ &session->qat_cipher_alg) != 0) {
+ PMD_DRV_LOG(ERR, "Invalid DES cipher key size");
+ goto error_out;
+ }
+ session->qat_mode = ICP_QAT_HW_CIPHER_CBC_MODE;
+ break;
case RTE_CRYPTO_CIPHER_3DES_CTR:
if (qat_alg_validate_3des_key(cipher_xform->key.length,
&session->qat_cipher_alg) != 0) {
@@ -839,7 +867,6 @@ unsigned qat_crypto_sym_get_session_private_size(
return RTE_ALIGN_CEIL(sizeof(struct qat_session), 8);
}
-
uint16_t
qat_pmd_enqueue_op_burst(void *qp, struct rte_crypto_op **ops,
uint16_t nb_ops)
--
2.1.0
^ permalink raw reply related
* [PATCH 3/3] app/test: add DES tests to Intel QAT crypto test suite
From: Arek Kusztal @ 2016-12-02 14:16 UTC (permalink / raw)
To: dev
Cc: fiona.trahe, pablo.de.lara.guarch, john.griffin, deepak.k.jain,
Arek Kusztal
In-Reply-To: <1480688162-27474-1-git-send-email-arkadiuszx.kusztal@intel.com>
This commit adds tests of Data Encryption Standard (DES)
algorithm to Intel QuickAssist technology crypto test suites
Signed-off-by: Arek Kusztal <arkadiuszx.kusztal@intel.com>
---
app/test/test_cryptodev.c | 18 +++++
app/test/test_cryptodev_blockcipher.c | 5 ++
app/test/test_cryptodev_blockcipher.h | 3 +-
app/test/test_cryptodev_des_test_vectors.h | 110 +++++++++++++++++++++++++++++
4 files changed, 135 insertions(+), 1 deletion(-)
diff --git a/app/test/test_cryptodev.c b/app/test/test_cryptodev.c
index 00dced5..23e56ec 100644
--- a/app/test/test_cryptodev.c
+++ b/app/test/test_cryptodev.c
@@ -3829,6 +3829,22 @@ test_3DES_chain_qat_all(void)
}
static int
+test_DES_cipheronly_qat_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpool, ts_params->valid_devs[0],
+ RTE_CRYPTODEV_QAT_SYM_PMD,
+ BLKCIPHER_DES_CIPHERONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
test_3DES_cipheronly_qat_all(void)
{
struct crypto_testsuite_params *ts_params = &testsuite_params;
@@ -6053,6 +6069,8 @@ static struct unit_test_suite cryptodev_qat_testsuite = {
TEST_CASE_ST(ut_setup, ut_teardown, test_3DES_chain_qat_all),
TEST_CASE_ST(ut_setup, ut_teardown,
test_3DES_cipheronly_qat_all),
+ TEST_CASE_ST(ut_setup, ut_teardown,
+ test_DES_cipheronly_qat_all),
TEST_CASE_ST(ut_setup, ut_teardown, test_stats),
/** AES GCM Authenticated Encryption */
diff --git a/app/test/test_cryptodev_blockcipher.c b/app/test/test_cryptodev_blockcipher.c
index 37b10cf..03dd073 100644
--- a/app/test/test_cryptodev_blockcipher.c
+++ b/app/test/test_cryptodev_blockcipher.c
@@ -489,6 +489,11 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
sizeof(triple_des_cipheronly_test_cases[0]);
tcs = triple_des_cipheronly_test_cases;
break;
+ case BLKCIPHER_DES_CIPHERONLY_TYPE:
+ n_test_cases = sizeof(des_cipheronly_test_cases) /
+ sizeof(des_cipheronly_test_cases[0]);
+ tcs = des_cipheronly_test_cases;
+ break;
case BLKCIPHER_AUTHONLY_TYPE:
n_test_cases = sizeof(hash_test_cases) /
sizeof(hash_test_cases[0]);
diff --git a/app/test/test_cryptodev_blockcipher.h b/app/test/test_cryptodev_blockcipher.h
index 04ff1ee..fe97e4c 100644
--- a/app/test/test_cryptodev_blockcipher.h
+++ b/app/test/test_cryptodev_blockcipher.h
@@ -67,7 +67,8 @@ enum blockcipher_test_type {
BLKCIPHER_AES_CIPHERONLY_TYPE, /* use aes_cipheronly_test_cases[] */
BLKCIPHER_3DES_CHAIN_TYPE, /* use triple_des_chain_test_cases[] */
BLKCIPHER_3DES_CIPHERONLY_TYPE, /* triple_des_cipheronly_test_cases[] */
- BLKCIPHER_AUTHONLY_TYPE /* use hash_test_cases[] */
+ BLKCIPHER_AUTHONLY_TYPE, /* use hash_test_cases[] */
+ BLKCIPHER_DES_CIPHERONLY_TYPE /* use des_cipheronly_test_cases[] */
};
struct blockcipher_test_case {
diff --git a/app/test/test_cryptodev_des_test_vectors.h b/app/test/test_cryptodev_des_test_vectors.h
index a1d2d97..388d87e 100644
--- a/app/test/test_cryptodev_des_test_vectors.h
+++ b/app/test/test_cryptodev_des_test_vectors.h
@@ -474,6 +474,75 @@ static const uint8_t ciphertext512_des128cbc[] = {
0x43, 0xfe, 0xf1, 0x10, 0x14, 0xf1, 0x91, 0xcc
};
+
+static const uint8_t ciphertext512_des[] = {
+ 0x1A, 0x46, 0xDB, 0x69, 0x43, 0x45, 0x0F, 0x2F,
+ 0xDC, 0x27, 0xF9, 0x41, 0x0E, 0x01, 0x58, 0xB4,
+ 0x5E, 0xCC, 0x13, 0xF5, 0x92, 0x99, 0xE4, 0xF2,
+ 0xD5, 0xF9, 0x16, 0xFE, 0x0F, 0x7E, 0xDE, 0xA0,
+ 0xF5, 0x32, 0xFE, 0x20, 0x67, 0x93, 0xCA, 0xE1,
+ 0x8E, 0x4D, 0x72, 0xA3, 0x50, 0x72, 0x14, 0x15,
+ 0x70, 0xE7, 0xAB, 0x49, 0x25, 0x88, 0x0E, 0x01,
+ 0x5C, 0x52, 0x87, 0xE2, 0x27, 0xDC, 0xD4, 0xD1,
+ 0x14, 0x1B, 0x08, 0x9F, 0x42, 0x48, 0x93, 0xA9,
+ 0xD1, 0x2F, 0x2C, 0x69, 0x48, 0x16, 0x59, 0xCF,
+ 0x8B, 0xF6, 0x8B, 0xD9, 0x34, 0xD4, 0xD7, 0xE4,
+ 0xAE, 0x35, 0xFD, 0xDA, 0x73, 0xBE, 0xDC, 0x6B,
+ 0x10, 0x90, 0x75, 0x2D, 0x4C, 0x14, 0x37, 0x8B,
+ 0xC8, 0xC7, 0xDF, 0x6E, 0x6F, 0xED, 0xF3, 0xE3,
+ 0xD3, 0x21, 0x29, 0xCD, 0x06, 0xB6, 0x5B, 0xF4,
+ 0xB9, 0xBD, 0x77, 0xA2, 0xF7, 0x91, 0xF4, 0x95,
+ 0xF0, 0xE0, 0x62, 0x03, 0x46, 0xAE, 0x1B, 0xEB,
+ 0xE2, 0xA9, 0xCF, 0xB9, 0x0E, 0x3B, 0xB9, 0xDA,
+ 0x5C, 0x1B, 0x45, 0x3F, 0xDD, 0xCC, 0xCC, 0xB3,
+ 0xF0, 0xDD, 0x36, 0x26, 0x11, 0x57, 0x97, 0xA7,
+ 0xF6, 0xF4, 0xE1, 0x4F, 0xBB, 0x31, 0xBB, 0x07,
+ 0x4B, 0xA3, 0xB4, 0x83, 0xF9, 0x23, 0xA1, 0xCD,
+ 0x8C, 0x1C, 0x76, 0x92, 0x45, 0xA5, 0xEB, 0x7D,
+ 0xEB, 0x22, 0x88, 0xB1, 0x9F, 0xFB, 0xE9, 0x06,
+ 0x8F, 0x67, 0xA6, 0x8A, 0xB7, 0x0B, 0xCD, 0x8F,
+ 0x34, 0x40, 0x4F, 0x4F, 0xAD, 0xA0, 0xF2, 0xDC,
+ 0x2C, 0x53, 0xE1, 0xCA, 0xA5, 0x7A, 0x03, 0xEF,
+ 0x08, 0x00, 0xCC, 0x52, 0xA6, 0xAB, 0x56, 0xD2,
+ 0xF1, 0xCD, 0xC7, 0xED, 0xBE, 0xCB, 0x78, 0x37,
+ 0x4B, 0x61, 0xA9, 0xD2, 0x3C, 0x8D, 0xCC, 0xFD,
+ 0x21, 0xFD, 0x0F, 0xE4, 0x4E, 0x3D, 0x6F, 0x8F,
+ 0x2A, 0xEC, 0x69, 0xFA, 0x20, 0x50, 0x99, 0x35,
+ 0xA1, 0xCC, 0x3B, 0xFD, 0xD6, 0xAC, 0xE9, 0xBE,
+ 0x14, 0xF1, 0xBC, 0x71, 0x70, 0xFE, 0x13, 0xD1,
+ 0x48, 0xCC, 0xBE, 0x7B, 0xCB, 0xC0, 0x20, 0xD9,
+ 0x28, 0xD7, 0xD4, 0x0F, 0x66, 0x7A, 0x60, 0xAB,
+ 0x20, 0xA9, 0x23, 0x41, 0x03, 0x34, 0xC3, 0x63,
+ 0x91, 0x69, 0x02, 0xD5, 0xBC, 0x41, 0xDA, 0xA8,
+ 0xD1, 0x48, 0xC9, 0x8E, 0x4F, 0xCD, 0x0F, 0x21,
+ 0x5B, 0x4D, 0x5F, 0xF5, 0x1B, 0x2A, 0x44, 0x10,
+ 0x16, 0xA7, 0xFD, 0xC0, 0x55, 0xE1, 0x98, 0xBB,
+ 0x76, 0xB5, 0xAB, 0x39, 0x6B, 0x9B, 0xAB, 0x85,
+ 0x45, 0x4B, 0x9C, 0x64, 0x7D, 0x78, 0x3F, 0x61,
+ 0x22, 0xB1, 0xDE, 0x0E, 0x39, 0x2B, 0x21, 0x26,
+ 0xE2, 0x1D, 0x5A, 0xD7, 0xAC, 0xDF, 0xD4, 0x12,
+ 0x69, 0xD1, 0xE8, 0x9B, 0x1A, 0xCE, 0x6C, 0xA0,
+ 0x3B, 0x23, 0xDC, 0x03, 0x2B, 0x97, 0x16, 0xD0,
+ 0xD0, 0x46, 0x98, 0x36, 0x53, 0xCE, 0x88, 0x6E,
+ 0xCA, 0x2C, 0x15, 0x0E, 0x49, 0xED, 0xBE, 0xE5,
+ 0xBF, 0xBD, 0x7B, 0xC2, 0x21, 0xE1, 0x09, 0xFF,
+ 0x71, 0xA8, 0xBE, 0x8F, 0xB4, 0x1D, 0x25, 0x5C,
+ 0x37, 0xCA, 0x26, 0xD2, 0x1E, 0x63, 0xE1, 0x7F,
+ 0x0D, 0x89, 0x10, 0xEF, 0x78, 0xB0, 0xDB, 0xD0,
+ 0x72, 0x44, 0x60, 0x1D, 0xCF, 0x7C, 0x25, 0x1A,
+ 0xBB, 0xC3, 0x92, 0x53, 0x8E, 0x9F, 0x27, 0xC7,
+ 0xE8, 0x08, 0xFC, 0x5D, 0x50, 0x3E, 0xFC, 0xB0,
+ 0x00, 0xE2, 0x48, 0xB2, 0x4B, 0xF8, 0xF2, 0xE3,
+ 0xD3, 0x8B, 0x71, 0x64, 0xB8, 0xF0, 0x6E, 0x4A,
+ 0x23, 0xA0, 0xA4, 0x88, 0xA4, 0x36, 0x45, 0x6B,
+ 0x5A, 0xE7, 0x57, 0x65, 0xEA, 0xC9, 0xF8, 0xE8,
+ 0x7A, 0x80, 0x22, 0x67, 0x1A, 0x05, 0xF2, 0x78,
+ 0x81, 0x17, 0xCD, 0x87, 0xFB, 0x0D, 0x25, 0x84,
+ 0x49, 0x06, 0x25, 0xCE, 0xFC, 0x38, 0x06, 0x18,
+ 0x2E, 0x1D, 0xE1, 0x33, 0x97, 0xB6, 0x7E, 0xAB,
+};
+
+
static const struct blockcipher_test_data
triple_des128cbc_test_vector = {
.crypto_algo = RTE_CRYPTO_CIPHER_3DES_CBC,
@@ -752,6 +821,47 @@ triple_des192cbc_hmac_sha1_test_vector = {
}
};
+static const struct blockcipher_test_data
+des_cbc_test_vector = {
+ .crypto_algo = RTE_CRYPTO_CIPHER_DES_CBC,
+ .cipher_key = {
+ .data = {
+ 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2
+ },
+ .len = 8
+ },
+ .iv = {
+ .data = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ },
+ .len = 8
+ },
+ .plaintext = {
+ .data = plaintext_des,
+ .len = 512
+ },
+ .ciphertext = {
+ .data = ciphertext512_des,
+ .len = 512
+ },
+};
+
+static const struct blockcipher_test_case des_cipheronly_test_cases[] = {
+ {
+ .test_descr = "DES-CBC Encryption",
+ .test_data = &des_cbc_test_vector,
+ .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
+ .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT
+ },
+ {
+ .test_descr = "DES-CBC Decryption",
+ .test_data = &des_cbc_test_vector,
+ .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
+ .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT
+ },
+
+};
+
static const struct blockcipher_test_case triple_des_chain_test_cases[] = {
{
.test_descr = "3DES-128-CBC HMAC-SHA1 Encryption Digest",
--
2.1.0
^ permalink raw reply related
* Re: [PATCH 00/31] Support VFD and DPDK PF + kernel VF on i40e
From: Thomas Monjalon @ 2016-12-02 14:16 UTC (permalink / raw)
To: wenzhuo.lu, bernard.iremonger, ferruh.yigit; +Cc: dev
In-Reply-To: <1480637533-37425-1-git-send-email-wenzhuo.lu@intel.com>
Do you agree to copy the remaining VF-specific functions from the
generic ethdev API to ixgbe in 17.02?
After a deprecation notice, we could remove them from the generic API in 17.05.
So we will have a consistent status in 17.05 regarding VF functions.
After some time (and experience) we will be able to discuss wether
we need something more to access to these specific features.
^ permalink raw reply
* Re: [PATCH 00/31] Support VFD and DPDK PF + kernel VF on i40e
From: Iremonger, Bernard @ 2016-12-02 14:25 UTC (permalink / raw)
To: Thomas Monjalon, Lu, Wenzhuo, Yigit, Ferruh; +Cc: dev@dpdk.org
In-Reply-To: <1481402.BuWyjbRiDQ@xps13>
Hi Thomas,
> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Friday, December 2, 2016 2:16 PM
> To: Lu, Wenzhuo <wenzhuo.lu@intel.com>; Iremonger, Bernard
> <bernard.iremonger@intel.com>; Yigit, Ferruh <ferruh.yigit@intel.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 00/31] Support VFD and DPDK PF + kernel VF
> on i40e
>
> Do you agree to copy the remaining VF-specific functions from the generic
> ethdev API to ixgbe in 17.02?
> After a deprecation notice, we could remove them from the generic API in
> 17.05.
> So we will have a consistent status in 17.05 regarding VF functions.
>
> After some time (and experience) we will be able to discuss wether we need
> something more to access to these specific features.
I had intended to copy the remaining VF-specific functions from the generic ethdev API to ixgbe in 17.02 and a deprecation notice was sent in 16.11.
This work was parked in order work on the VF-specfic functionsfor the i40e. Is it ok to submit patches for this work after the V1 deadline (today)?
Regards,
Bernard.
^ permalink raw reply
* [PATCH 0/3] virtio_user as an alternative exception path
From: Jianfeng Tan @ 2016-12-02 14:31 UTC (permalink / raw)
To: dev; +Cc: yuanhan.liu, ferruh.yigit, cunming.liang, Jianfeng Tan
In v16.07, we upstreamed a virtual device, virtio_user (with vhost-user
as the backend). The path to go with a vhost-kernel backend has been
dropped for bad performance comparing to vhost-user and code simplicity.
But after a second thought, virtio_user + vhost-kernel is a good
candidate as an exceptional path, such as KNI, which exchanges packets
with kernel networking stack.
- maintenance: vhost-net (kernel) is upstreamed and extensively used
kernel module. We don't need any out-of-tree module like KNI.
- performance: as with KNI, this solution would use one or more
kthreads to send/receive packets from user space DPDK applications,
which has little impact on user space polling thread (except that
it might enter into kernel space to wake up those kthreads if
necessary.
- features: vhost-net is born to be a networking solution, which has
lots of networking related featuers, like multi queue, tso, multi-seg
mbuf, etc.
Known issues for current version:
- Multiqueue not supported yet.
- Offloading is completely enabled yet; to enhance, we will translate
the virtio header info into mbuf metadata when receiving packets
from kernel; and translate mbuf metadata info into virtio header
when sending packets to kernel.
Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
Jianfeng Tan (3):
net/virtio_user: add vhost layer
net/virtio_user: add vhost kernel support
net/virtio_user: fix wrongly set features
drivers/net/virtio/Makefile | 2 +
drivers/net/virtio/virtio_user/vhost.c | 181 ++++++++++
drivers/net/virtio/virtio_user/vhost.h | 73 ++--
drivers/net/virtio/virtio_user/vhost_kernel.c | 413 +++++++++++++++++++++++
drivers/net/virtio/virtio_user/vhost_user.c | 81 +++--
drivers/net/virtio/virtio_user/virtio_user_dev.c | 49 ++-
drivers/net/virtio/virtio_user/virtio_user_dev.h | 3 +-
drivers/net/virtio/virtio_user_ethdev.c | 4 +-
8 files changed, 708 insertions(+), 98 deletions(-)
create mode 100644 drivers/net/virtio/virtio_user/vhost.c
create mode 100644 drivers/net/virtio/virtio_user/vhost_kernel.c
--
2.7.4
^ permalink raw reply
* [PATCH 1/3] net/virtio_user: add vhost layer
From: Jianfeng Tan @ 2016-12-02 14:31 UTC (permalink / raw)
To: dev; +Cc: yuanhan.liu, ferruh.yigit, cunming.liang, Jianfeng Tan
In-Reply-To: <1480689075-66977-1-git-send-email-jianfeng.tan@intel.com>
To support vhost kernel as the backend of net_virtio_user in comming
patches, we abstract a vhost layer to hide all vhost_user functions.
- Move vhost_user specific structs and macros into vhost_user.c,
and only keep common definitions in vhost.h;
- Add a struct vhost_internal, and an array to store vhost_user and
vhost_kernel backends; in multiqueue case, vhost_user has only
one vhost FD, but vhost_kernel would have multiple FDs (equal to
# of queues), so we turn to use an id to index the backend info;
- Add a struct vhost_ops depending on different type of backends.
Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
---
drivers/net/virtio/Makefile | 1 +
drivers/net/virtio/virtio_user/vhost.c | 162 +++++++++++++++++++++++
drivers/net/virtio/virtio_user/vhost.h | 68 +++++-----
drivers/net/virtio/virtio_user/vhost_user.c | 81 ++++++++----
drivers/net/virtio/virtio_user/virtio_user_dev.c | 47 +++----
drivers/net/virtio/virtio_user/virtio_user_dev.h | 2 +-
6 files changed, 266 insertions(+), 95 deletions(-)
create mode 100644 drivers/net/virtio/virtio_user/vhost.c
diff --git a/drivers/net/virtio/Makefile b/drivers/net/virtio/Makefile
index 97972a6..17f7129 100644
--- a/drivers/net/virtio/Makefile
+++ b/drivers/net/virtio/Makefile
@@ -59,6 +59,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_rxtx_simple_neon.c
endif
ifeq ($(CONFIG_RTE_VIRTIO_USER),y)
+SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user/vhost.c
SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user/vhost_user.c
SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user/virtio_user_dev.c
SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user_ethdev.c
diff --git a/drivers/net/virtio/virtio_user/vhost.c b/drivers/net/virtio/virtio_user/vhost.c
new file mode 100644
index 0000000..09e2e92
--- /dev/null
+++ b/drivers/net/virtio/virtio_user/vhost.c
@@ -0,0 +1,162 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "vhost.h"
+
+#define VHOST_MAX_DEVICES 8
+
+static struct vhost_internal internals[VHOST_MAX_DEVICES];
+
+static inline int
+vhost_internal_valid_vid(int vid)
+{
+ if (vid < 0 || vid >= VHOST_MAX_DEVICES)
+ return 0;
+
+ if (!internals[vid].ops)
+ return 0;
+
+ return 1;
+}
+
+static int
+vhost_internal_alloc(void)
+{
+ int i;
+
+ for (i = 0; i < VHOST_MAX_DEVICES; ++i)
+ if (internals[i].ops == NULL)
+ break;
+
+ if (i >= VHOST_MAX_DEVICES)
+ return -1;
+
+ internals[i].features = 0;
+
+ internals[i].vhostfd = -1;
+
+ return 0;
+}
+
+static void
+vhost_internal_free(int id)
+{
+ internals[id].ops = NULL;
+
+ if (internals[id].vhostfd >= 0)
+ close(internals[id].vhostfd);
+}
+
+
+static int
+is_vhost_user_by_type(const char *path)
+{
+ struct stat sb;
+
+ if (stat(path, &sb) == -1)
+ return 0;
+
+ return S_ISSOCK(sb.st_mode);
+}
+
+int
+vhost_setup(const char *path)
+{
+ int ret = -1;
+ int vid = vhost_internal_alloc();
+
+ if (vid < 0) {
+ PMD_DRV_LOG(ERR, "exceeding %d devices", VHOST_MAX_DEVICES);
+ return -1;
+ }
+
+ if (is_vhost_user_by_type(path)) {
+ ret = vhost_ops_user.setup(&internals[vid], path);
+ internals[vid].ops = &vhost_ops_user;
+ }
+
+ if (ret < 0)
+ vhost_internal_free(vid);
+
+ return vid;
+}
+
+static const char * const vhost_msg_strings[] = {
+ [VHOST_USER_SET_OWNER] = "VHOST_USER_SET_OWNER",
+ [VHOST_USER_RESET_OWNER] = "VHOST_USER_RESET_OWNER",
+ [VHOST_USER_SET_FEATURES] = "VHOST_USER_SET_FEATURES",
+ [VHOST_USER_GET_FEATURES] = "VHOST_USER_GET_FEATURES",
+ [VHOST_USER_SET_VRING_CALL] = "VHOST_USER_SET_VRING_CALL",
+ [VHOST_USER_SET_VRING_NUM] = "VHOST_USER_SET_VRING_NUM",
+ [VHOST_USER_SET_VRING_BASE] = "VHOST_USER_SET_VRING_BASE",
+ [VHOST_USER_GET_VRING_BASE] = "VHOST_USER_GET_VRING_BASE",
+ [VHOST_USER_SET_VRING_ADDR] = "VHOST_USER_SET_VRING_ADDR",
+ [VHOST_USER_SET_VRING_KICK] = "VHOST_USER_SET_VRING_KICK",
+ [VHOST_USER_SET_MEM_TABLE] = "VHOST_USER_SET_MEM_TABLE",
+ [VHOST_USER_SET_VRING_ENABLE] = "VHOST_USER_SET_VRING_ENABLE",
+ NULL,
+};
+
+int
+vhost_call(int vid, enum vhost_user_request req, void *arg)
+{
+ RTE_SET_USED(vhost_msg_strings);
+ PMD_DRV_LOG(INFO, "%s", vhost_msg_strings[req]);
+
+ if (!vhost_internal_valid_vid(vid))
+ return -1;
+
+ return internals[vid].ops->control(&internals[vid], req, arg);
+}
+
+int
+vhost_enable_queue_pair(int vid, uint16_t pair_idx, int enable)
+{
+ if (!vhost_internal_valid_vid(vid))
+ return -1;
+
+ return internals[vid].ops->enable_qp(&internals[vid], pair_idx, enable);
+}
+
+void
+vhost_close(int vid)
+{
+ if (!vhost_internal_valid_vid(vid))
+ return;
+
+ vhost_internal_free(vid);
+}
diff --git a/drivers/net/virtio/virtio_user/vhost.h b/drivers/net/virtio/virtio_user/vhost.h
index 7adb55f..b476ecc 100644
--- a/drivers/net/virtio/virtio_user/vhost.h
+++ b/drivers/net/virtio/virtio_user/vhost.h
@@ -42,8 +42,6 @@
#include "../virtio_logs.h"
#include "../virtqueue.h"
-#define VHOST_MEMORY_MAX_NREGIONS 8
-
struct vhost_vring_state {
unsigned int index;
unsigned int num;
@@ -105,42 +103,38 @@ struct vhost_memory_region {
uint64_t mmap_offset;
};
-struct vhost_memory {
- uint32_t nregions;
- uint32_t padding;
- struct vhost_memory_region regions[VHOST_MEMORY_MAX_NREGIONS];
+struct vhost_ops;
+
+struct vhost_internal {
+ /* for both vhost-user and vhost-kernel */
+ uint64_t features;
+ struct vhost_ops *ops;
+
+ /* for vhost-user */
+ int vhostfd;
+
+ /* for vhost-kernel */
+};
+
+typedef int (*vhost_setup_t)(struct vhost_internal *internal,
+ const char *path);
+typedef int (*vhost_control_t)(struct vhost_internal *internal,
+ enum vhost_user_request req,
+ void *arg);
+typedef int (*vhost_enable_qp_t)(struct vhost_internal *internal,
+ uint16_t pair_idx,
+ int enable);
+
+struct vhost_ops {
+ vhost_setup_t setup;
+ vhost_control_t control;
+ vhost_enable_qp_t enable_qp;
};
-struct vhost_user_msg {
- enum vhost_user_request request;
-
-#define VHOST_USER_VERSION_MASK 0x3
-#define VHOST_USER_REPLY_MASK (0x1 << 2)
- uint32_t flags;
- uint32_t size; /* the following payload size */
- union {
-#define VHOST_USER_VRING_IDX_MASK 0xff
-#define VHOST_USER_VRING_NOFD_MASK (0x1 << 8)
- uint64_t u64;
- struct vhost_vring_state state;
- struct vhost_vring_addr addr;
- struct vhost_memory memory;
- } payload;
- int fds[VHOST_MEMORY_MAX_NREGIONS];
-} __attribute((packed));
-
-#define VHOST_USER_HDR_SIZE offsetof(struct vhost_user_msg, payload.u64)
-#define VHOST_USER_PAYLOAD_SIZE \
- (sizeof(struct vhost_user_msg) - VHOST_USER_HDR_SIZE)
-
-/* The version of the protocol we support */
-#define VHOST_USER_VERSION 0x1
-
-#define VHOST_USER_F_PROTOCOL_FEATURES 30
-#define VHOST_USER_MQ (1ULL << VHOST_USER_F_PROTOCOL_FEATURES)
-
-int vhost_user_sock(int vhostfd, enum vhost_user_request req, void *arg);
-int vhost_user_setup(const char *path);
-int vhost_user_enable_queue_pair(int vhostfd, uint16_t pair_idx, int enable);
+struct vhost_ops vhost_ops_user;
+int vhost_setup(const char *path);
+int vhost_call(int vid, enum vhost_user_request req, void *arg);
+int vhost_enable_queue_pair(int vid, uint16_t pair_idx, int enable);
+void vhost_close(int vid);
#endif
diff --git a/drivers/net/virtio/virtio_user/vhost_user.c b/drivers/net/virtio/virtio_user/vhost_user.c
index 082e821..afd18ec 100644
--- a/drivers/net/virtio/virtio_user/vhost_user.c
+++ b/drivers/net/virtio/virtio_user/vhost_user.c
@@ -42,6 +42,38 @@
#include "vhost.h"
+/* The version of the protocol we support */
+#define VHOST_USER_VERSION 0x1
+#define VHOST_MEMORY_MAX_NREGIONS 8
+
+struct vhost_memory {
+ uint32_t nregions;
+ uint32_t padding;
+ struct vhost_memory_region regions[VHOST_MEMORY_MAX_NREGIONS];
+};
+
+struct vhost_user_msg {
+ enum vhost_user_request request;
+
+#define VHOST_USER_VERSION_MASK 0x3
+#define VHOST_USER_REPLY_MASK (0x1 << 2)
+ uint32_t flags;
+ uint32_t size; /* the following payload size */
+ union {
+#define VHOST_USER_VRING_IDX_MASK 0xff
+#define VHOST_USER_VRING_NOFD_MASK (0x1 << 8)
+ uint64_t u64;
+ struct vhost_vring_state state;
+ struct vhost_vring_addr addr;
+ struct vhost_memory memory;
+ } payload;
+ int fds[VHOST_MEMORY_MAX_NREGIONS];
+} __attribute((packed));
+
+#define VHOST_USER_HDR_SIZE offsetof(struct vhost_user_msg, payload.u64)
+#define VHOST_USER_PAYLOAD_SIZE \
+ (sizeof(struct vhost_user_msg) - VHOST_USER_HDR_SIZE)
+
static int
vhost_user_write(int fd, void *buf, int len, int *fds, int fd_num)
{
@@ -223,24 +255,10 @@ prepare_vhost_memory_user(struct vhost_user_msg *msg, int fds[])
static struct vhost_user_msg m;
-static const char * const vhost_msg_strings[] = {
- [VHOST_USER_SET_OWNER] = "VHOST_USER_SET_OWNER",
- [VHOST_USER_RESET_OWNER] = "VHOST_USER_RESET_OWNER",
- [VHOST_USER_SET_FEATURES] = "VHOST_USER_SET_FEATURES",
- [VHOST_USER_GET_FEATURES] = "VHOST_USER_GET_FEATURES",
- [VHOST_USER_SET_VRING_CALL] = "VHOST_USER_SET_VRING_CALL",
- [VHOST_USER_SET_VRING_NUM] = "VHOST_USER_SET_VRING_NUM",
- [VHOST_USER_SET_VRING_BASE] = "VHOST_USER_SET_VRING_BASE",
- [VHOST_USER_GET_VRING_BASE] = "VHOST_USER_GET_VRING_BASE",
- [VHOST_USER_SET_VRING_ADDR] = "VHOST_USER_SET_VRING_ADDR",
- [VHOST_USER_SET_VRING_KICK] = "VHOST_USER_SET_VRING_KICK",
- [VHOST_USER_SET_MEM_TABLE] = "VHOST_USER_SET_MEM_TABLE",
- [VHOST_USER_SET_VRING_ENABLE] = "VHOST_USER_SET_VRING_ENABLE",
- NULL,
-};
-
-int
-vhost_user_sock(int vhostfd, enum vhost_user_request req, void *arg)
+static int
+vhost_user_sock(struct vhost_internal *internal,
+ enum vhost_user_request req,
+ void *arg)
{
struct vhost_user_msg msg;
struct vhost_vring_file *file = 0;
@@ -248,11 +266,9 @@ vhost_user_sock(int vhostfd, enum vhost_user_request req, void *arg)
int fds[VHOST_MEMORY_MAX_NREGIONS];
int fd_num = 0;
int i, len;
+ int vhostfd = internal->vhostfd;
RTE_SET_USED(m);
- RTE_SET_USED(vhost_msg_strings);
-
- PMD_DRV_LOG(INFO, "%s", vhost_msg_strings[req]);
msg.request = req;
msg.flags = VHOST_USER_VERSION;
@@ -323,8 +339,8 @@ vhost_user_sock(int vhostfd, enum vhost_user_request req, void *arg)
len = VHOST_USER_HDR_SIZE + msg.size;
if (vhost_user_write(vhostfd, &msg, len, fds, fd_num) < 0) {
- PMD_DRV_LOG(ERR, "%s failed: %s",
- vhost_msg_strings[req], strerror(errno));
+ PMD_DRV_LOG(ERR, "fail to write vhost user msg: %s",
+ strerror(errno));
return -1;
}
@@ -378,8 +394,8 @@ vhost_user_sock(int vhostfd, enum vhost_user_request req, void *arg)
* - (-1) if fail to set up;
* - (>=0) if successful, and it is the fd to vhostfd.
*/
-int
-vhost_user_setup(const char *path)
+static int
+vhost_user_setup(struct vhost_internal *internal, const char *path)
{
int fd;
int flag;
@@ -404,11 +420,14 @@ vhost_user_setup(const char *path)
return -1;
}
+ internal->vhostfd = fd;
+
return fd;
}
-int
-vhost_user_enable_queue_pair(int vhostfd, uint16_t pair_idx, int enable)
+static int
+vhost_user_enable_queue_pair(struct vhost_internal *internal,
+ uint16_t pair_idx, int enable)
{
int i;
@@ -418,10 +437,16 @@ vhost_user_enable_queue_pair(int vhostfd, uint16_t pair_idx, int enable)
.num = enable,
};
- if (vhost_user_sock(vhostfd,
+ if (vhost_user_sock(internal,
VHOST_USER_SET_VRING_ENABLE, &state))
return -1;
}
return 0;
}
+
+struct vhost_ops vhost_ops_user = {
+ .setup = vhost_user_setup,
+ .control = vhost_user_sock,
+ .enable_qp = vhost_user_enable_queue_pair
+};
diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.c b/drivers/net/virtio/virtio_user/virtio_user_dev.c
index e239e0e..3aef5f6 100644
--- a/drivers/net/virtio/virtio_user/virtio_user_dev.c
+++ b/drivers/net/virtio/virtio_user/virtio_user_dev.c
@@ -64,7 +64,7 @@ virtio_user_create_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
}
file.index = queue_sel;
file.fd = callfd;
- vhost_user_sock(dev->vhostfd, VHOST_USER_SET_VRING_CALL, &file);
+ vhost_call(dev->vid, VHOST_USER_SET_VRING_CALL, &file);
dev->callfds[queue_sel] = callfd;
return 0;
@@ -88,12 +88,12 @@ virtio_user_kick_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
state.index = queue_sel;
state.num = vring->num;
- vhost_user_sock(dev->vhostfd, VHOST_USER_SET_VRING_NUM, &state);
+ vhost_call(dev->vid, VHOST_USER_SET_VRING_NUM, &state);
state.num = 0; /* no reservation */
- vhost_user_sock(dev->vhostfd, VHOST_USER_SET_VRING_BASE, &state);
+ vhost_call(dev->vid, VHOST_USER_SET_VRING_BASE, &state);
- vhost_user_sock(dev->vhostfd, VHOST_USER_SET_VRING_ADDR, &addr);
+ vhost_call(dev->vid, VHOST_USER_SET_VRING_ADDR, &addr);
/* Of all per virtqueue MSGs, make sure VHOST_USER_SET_VRING_KICK comes
* lastly because vhost depends on this msg to judge if
@@ -106,7 +106,7 @@ virtio_user_kick_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
}
file.index = queue_sel;
file.fd = kickfd;
- vhost_user_sock(dev->vhostfd, VHOST_USER_SET_VRING_KICK, &file);
+ vhost_call(dev->vid, VHOST_USER_SET_VRING_KICK, &file);
dev->kickfds[queue_sel] = kickfd;
return 0;
@@ -146,21 +146,18 @@ virtio_user_start_device(struct virtio_user_dev *dev)
if (virtio_user_queue_setup(dev, virtio_user_create_queue) < 0)
goto error;
- /* Step 1: set features
- * Make sure VHOST_USER_F_PROTOCOL_FEATURES is added if mq is enabled,
- * and VIRTIO_NET_F_MAC is stripped.
+ /* Step 1: set feature
+ * Strip VIRTIO_NET_F_MAC, as MAC address is handled in vdev init.
*/
features = dev->features;
- if (dev->max_queue_pairs > 1)
- features |= VHOST_USER_MQ;
features &= ~(1ull << VIRTIO_NET_F_MAC);
- ret = vhost_user_sock(dev->vhostfd, VHOST_USER_SET_FEATURES, &features);
+ ret = vhost_call(dev->vid, VHOST_USER_SET_FEATURES, &features);
if (ret < 0)
goto error;
PMD_DRV_LOG(INFO, "set features: %" PRIx64, features);
/* Step 2: share memory regions */
- ret = vhost_user_sock(dev->vhostfd, VHOST_USER_SET_MEM_TABLE, NULL);
+ ret = vhost_call(dev->vid, VHOST_USER_SET_MEM_TABLE, NULL);
if (ret < 0)
goto error;
@@ -171,7 +168,7 @@ virtio_user_start_device(struct virtio_user_dev *dev)
/* Step 4: enable queues
* we enable the 1st queue pair by default.
*/
- vhost_user_enable_queue_pair(dev->vhostfd, 0, 1);
+ vhost_enable_queue_pair(dev->vid, 0, 1);
return 0;
error:
@@ -181,7 +178,7 @@ virtio_user_start_device(struct virtio_user_dev *dev)
int virtio_user_stop_device(struct virtio_user_dev *dev)
{
- return vhost_user_sock(dev->vhostfd, VHOST_USER_RESET_OWNER, NULL);
+ return vhost_call(dev->vid, VHOST_USER_RESET_OWNER, NULL);
}
static inline void
@@ -215,19 +212,18 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues,
dev->queue_size = queue_size;
dev->mac_specified = 0;
parse_mac(dev, mac);
- dev->vhostfd = -1;
- dev->vhostfd = vhost_user_setup(dev->path);
- if (dev->vhostfd < 0) {
+ dev->vid = vhost_setup(dev->path);
+ if (dev->vid < 0) {
PMD_INIT_LOG(ERR, "backend set up fails");
return -1;
}
- if (vhost_user_sock(dev->vhostfd, VHOST_USER_SET_OWNER, NULL) < 0) {
+ if (vhost_call(dev->vid, VHOST_USER_SET_OWNER, NULL) < 0) {
PMD_INIT_LOG(ERR, "set_owner fails: %s", strerror(errno));
return -1;
}
- if (vhost_user_sock(dev->vhostfd, VHOST_USER_GET_FEATURES,
+ if (vhost_call(dev->vid, VHOST_USER_GET_FEATURES,
&dev->features) < 0) {
PMD_INIT_LOG(ERR, "get_features failed: %s", strerror(errno));
return -1;
@@ -253,13 +249,6 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues,
PMD_INIT_LOG(INFO, "vhost does not support ctrl-q");
}
- if (dev->max_queue_pairs > 1) {
- if (!(dev->features & VHOST_USER_MQ)) {
- PMD_INIT_LOG(ERR, "MQ not supported by the backend");
- return -1;
- }
- }
-
return 0;
}
@@ -273,7 +262,7 @@ virtio_user_dev_uninit(struct virtio_user_dev *dev)
close(dev->kickfds[i]);
}
- close(dev->vhostfd);
+ vhost_close(dev->vid);
}
static uint8_t
@@ -289,9 +278,9 @@ virtio_user_handle_mq(struct virtio_user_dev *dev, uint16_t q_pairs)
}
for (i = 0; i < q_pairs; ++i)
- ret |= vhost_user_enable_queue_pair(dev->vhostfd, i, 1);
+ ret |= vhost_enable_queue_pair(dev->vid, i, 1);
for (i = q_pairs; i < dev->max_queue_pairs; ++i)
- ret |= vhost_user_enable_queue_pair(dev->vhostfd, i, 0);
+ ret |= vhost_enable_queue_pair(dev->vid, i, 0);
dev->queue_pairs = q_pairs;
diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.h b/drivers/net/virtio/virtio_user/virtio_user_dev.h
index 33690b5..80efb6e 100644
--- a/drivers/net/virtio/virtio_user/virtio_user_dev.h
+++ b/drivers/net/virtio/virtio_user/virtio_user_dev.h
@@ -39,7 +39,7 @@
#include "../virtio_ring.h"
struct virtio_user_dev {
- int vhostfd;
+ int vid;
int callfds[VIRTIO_MAX_VIRTQUEUES * 2 + 1];
int kickfds[VIRTIO_MAX_VIRTQUEUES * 2 + 1];
int mac_specified;
--
2.7.4
^ permalink raw reply related
* [PATCH 2/3] net/virtio_user: add vhost kernel support
From: Jianfeng Tan @ 2016-12-02 14:31 UTC (permalink / raw)
To: dev; +Cc: yuanhan.liu, ferruh.yigit, cunming.liang, Jianfeng Tan
In-Reply-To: <1480689075-66977-1-git-send-email-jianfeng.tan@intel.com>
This patch add support vhost kernel support under vhost abstraction
layer.
Three main hook functions are added:
- vhost_kernel_setup() to open char device, each vq pair (Rx and Tx)
would need open it once;
- vhost_kernel_ioctl() to communicate control messages with vhost
kernel module;
- vhost_kernel_enable_queue_pair() to open tap device and set it
as the backend of corresonding vhost fd (that is to say, vq pair).
Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
---
drivers/net/virtio/Makefile | 1 +
drivers/net/virtio/virtio_user/vhost.c | 21 +-
drivers/net/virtio/virtio_user/vhost.h | 5 +
drivers/net/virtio/virtio_user/vhost_kernel.c | 413 ++++++++++++++++++++++++++
4 files changed, 439 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/virtio/virtio_user/vhost_kernel.c
diff --git a/drivers/net/virtio/Makefile b/drivers/net/virtio/Makefile
index 17f7129..f671f1f 100644
--- a/drivers/net/virtio/Makefile
+++ b/drivers/net/virtio/Makefile
@@ -61,6 +61,7 @@ endif
ifeq ($(CONFIG_RTE_VIRTIO_USER),y)
SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user/vhost.c
SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user/vhost_user.c
+SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user/vhost_kernel.c
SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user/virtio_user_dev.c
SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user_ethdev.c
endif
diff --git a/drivers/net/virtio/virtio_user/vhost.c b/drivers/net/virtio/virtio_user/vhost.c
index 09e2e92..5384992 100644
--- a/drivers/net/virtio/virtio_user/vhost.c
+++ b/drivers/net/virtio/virtio_user/vhost.c
@@ -56,7 +56,7 @@ vhost_internal_valid_vid(int vid)
static int
vhost_internal_alloc(void)
{
- int i;
+ int i, q;
for (i = 0; i < VHOST_MAX_DEVICES; ++i)
if (internals[i].ops == NULL)
@@ -69,16 +69,32 @@ vhost_internal_alloc(void)
internals[i].vhostfd = -1;
+ for (q = 0; q < VHOST_KERNEL_MAX_QUEUES; ++q) {
+ internals[i].vhostfds[q] = -1;
+ internals[i].tapfds[q] = -1;
+ }
+
return 0;
}
static void
vhost_internal_free(int id)
{
+ int q;
+
internals[id].ops = NULL;
if (internals[id].vhostfd >= 0)
close(internals[id].vhostfd);
+
+ for (q = 0; q < VHOST_KERNEL_MAX_QUEUES; ++q) {
+ if (internals[id].vhostfds[q] >= 0)
+ close(internals[id].vhostfds[q]);
+ if (internals[id].tapfds[q] >= 0)
+ close(internals[id].tapfds[q]);
+ }
+ if (internals[id].ifname)
+ free(internals[id].ifname);
}
@@ -107,6 +123,9 @@ vhost_setup(const char *path)
if (is_vhost_user_by_type(path)) {
ret = vhost_ops_user.setup(&internals[vid], path);
internals[vid].ops = &vhost_ops_user;
+ } else {
+ ret = vhost_ops_kernel.setup(&internals[vid], path);
+ internals[vid].ops = &vhost_ops_kernel;
}
if (ret < 0)
diff --git a/drivers/net/virtio/virtio_user/vhost.h b/drivers/net/virtio/virtio_user/vhost.h
index b476ecc..b6fd092 100644
--- a/drivers/net/virtio/virtio_user/vhost.h
+++ b/drivers/net/virtio/virtio_user/vhost.h
@@ -114,6 +114,10 @@ struct vhost_internal {
int vhostfd;
/* for vhost-kernel */
+ char *ifname;
+#define VHOST_KERNEL_MAX_QUEUES 8
+ int vhostfds[VHOST_KERNEL_MAX_QUEUES];
+ int tapfds[VHOST_KERNEL_MAX_QUEUES];
};
typedef int (*vhost_setup_t)(struct vhost_internal *internal,
@@ -132,6 +136,7 @@ struct vhost_ops {
};
struct vhost_ops vhost_ops_user;
+struct vhost_ops vhost_ops_kernel;
int vhost_setup(const char *path);
int vhost_call(int vid, enum vhost_user_request req, void *arg);
diff --git a/drivers/net/virtio/virtio_user/vhost_kernel.c b/drivers/net/virtio/virtio_user/vhost_kernel.c
new file mode 100644
index 0000000..9a9e8bd
--- /dev/null
+++ b/drivers/net/virtio/virtio_user/vhost_kernel.c
@@ -0,0 +1,413 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <string.h>
+#include <errno.h>
+
+#include <rte_memory.h>
+#include <rte_eal_memconfig.h>
+
+#include "vhost.h"
+
+struct vhost_memory_kernel {
+ uint32_t nregions;
+ uint32_t padding;
+ struct vhost_memory_region regions[0];
+};
+
+/* vhost kernel ioctls */
+#define VHOST_VIRTIO 0xAF
+#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
+#define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64)
+#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
+#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
+#define VHOST_SET_MEM_TABLE _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory_kernel)
+#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
+#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
+#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
+#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
+#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
+#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
+#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
+#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
+#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
+#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
+
+/* TUN ioctls */
+#define TUNSETIFF _IOW('T', 202, int)
+#define TUNGETFEATURES _IOR('T', 207, unsigned int)
+#define TUNSETOFFLOAD _IOW('T', 208, unsigned int)
+#define TUNGETIFF _IOR('T', 210, unsigned int)
+#define TUNSETSNDBUF _IOW('T', 212, int)
+#define TUNGETVNETHDRSZ _IOR('T', 215, int)
+#define TUNSETVNETHDRSZ _IOW('T', 216, int)
+#define TUNSETQUEUE _IOW('T', 217, int)
+#define TUNSETVNETLE _IOW('T', 220, int)
+#define TUNSETVNETBE _IOW('T', 222, int)
+
+/* TUNSETIFF ifr flags */
+#define IFF_TAP 0x0002
+#define IFF_NO_PI 0x1000
+#define IFF_ONE_QUEUE 0x2000
+#define IFF_VNET_HDR 0x4000
+#define IFF_MULTI_QUEUE 0x0100
+#define IFF_ATTACH_QUEUE 0x0200
+#define IFF_DETACH_QUEUE 0x0400
+
+/* Features for GSO (TUNSETOFFLOAD). */
+#define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */
+#define TUN_F_TSO4 0x02 /* I can handle TSO for IPv4 packets */
+#define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */
+#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */
+#define TUN_F_UFO 0x10 /* I can handle UFO packets */
+
+/* Constants */
+#define TUN_DEF_SNDBUF (1ull << 20)
+#define PATH_NET_TUN "/dev/net/tun"
+#define VHOST_KERNEL_MAX_REGIONS 64
+
+static uint64_t vhost_req_user_to_kernel[] = {
+ [VHOST_USER_SET_OWNER] = VHOST_SET_OWNER,
+ [VHOST_USER_RESET_OWNER] = VHOST_RESET_OWNER,
+ [VHOST_USER_SET_FEATURES] = VHOST_SET_FEATURES,
+ [VHOST_USER_GET_FEATURES] = VHOST_GET_FEATURES,
+ [VHOST_USER_SET_VRING_CALL] = VHOST_SET_VRING_CALL,
+ [VHOST_USER_SET_VRING_NUM] = VHOST_SET_VRING_NUM,
+ [VHOST_USER_SET_VRING_BASE] = VHOST_SET_VRING_BASE,
+ [VHOST_USER_GET_VRING_BASE] = VHOST_GET_VRING_BASE,
+ [VHOST_USER_SET_VRING_ADDR] = VHOST_SET_VRING_ADDR,
+ [VHOST_USER_SET_VRING_KICK] = VHOST_SET_VRING_KICK,
+ [VHOST_USER_SET_MEM_TABLE] = VHOST_SET_MEM_TABLE,
+};
+
+/* By default, vhost kernel module allows 64 regions, but DPDK allows
+ * 256 segments. As a relief, below function merges those virtually
+ * adjacent memsegs into one region.
+ */
+static struct vhost_memory_kernel *
+prepare_vhost_memory_kernel(void)
+{
+ uint32_t i, j, k = 0;
+ struct rte_memseg *seg;
+ struct vhost_memory_region *mr;
+ struct vhost_memory_kernel *vm;
+
+ vm = malloc(sizeof(struct vhost_memory_kernel) +
+ VHOST_KERNEL_MAX_REGIONS *
+ sizeof(struct vhost_memory_region));
+
+ for (i = 0; i < RTE_MAX_MEMSEG; ++i) {
+ seg = &rte_eal_get_configuration()->mem_config->memseg[i];
+ if (!seg->addr)
+ break;
+
+ int new_region = 1;
+
+ for (j = 0; j < k; ++j) {
+ mr = &vm->regions[j];
+
+ if (mr->userspace_addr + mr->memory_size ==
+ (uint64_t)seg->addr) {
+ mr->memory_size += seg->len;
+ new_region = 0;
+ break;
+ }
+
+ if ((uint64_t)seg->addr + seg->len ==
+ mr->userspace_addr) {
+ mr->guest_phys_addr = (uint64_t)seg->addr;
+ mr->userspace_addr = (uint64_t)seg->addr;
+ mr->memory_size += seg->len;
+ new_region = 0;
+ break;
+ }
+ }
+
+ if (new_region == 0)
+ continue;
+
+ mr = &vm->regions[k++];
+ mr->guest_phys_addr = (uint64_t)seg->addr; /* use vaddr here! */
+ mr->userspace_addr = (uint64_t)seg->addr;
+ mr->memory_size = seg->len;
+ mr->mmap_offset = 0;
+
+ if (k >= VHOST_KERNEL_MAX_REGIONS) {
+ free(vm);
+ return NULL;
+ }
+ }
+
+ vm->nregions = k;
+ vm->padding = 0;
+ return vm;
+}
+
+static const uint64_t guest_offloads_mask =
+ (1ULL << VIRTIO_NET_F_GUEST_CSUM) |
+ (1ULL << VIRTIO_NET_F_GUEST_TSO4) |
+ (1ULL << VIRTIO_NET_F_GUEST_TSO6) |
+ (1ULL << VIRTIO_NET_F_GUEST_ECN) |
+ (1ULL << VIRTIO_NET_F_GUEST_UFO);
+
+static int
+vhost_kernel_ioctl(struct vhost_internal *internal,
+ enum vhost_user_request req,
+ void *arg)
+{
+ int i, ret = -1;
+ uint64_t req_kernel;
+ struct vhost_memory_kernel *vm = NULL;
+
+ req_kernel = vhost_req_user_to_kernel[req];
+
+ if (req_kernel == VHOST_SET_MEM_TABLE) {
+ vm = prepare_vhost_memory_kernel();
+ if (!vm)
+ return -1;
+ arg = (void *)vm;
+ }
+
+ /* Does not work when VIRTIO_F_IOMMU_PLATFORM now, why? */
+ if (req_kernel == VHOST_SET_FEATURES)
+ *(uint64_t *)arg &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM);
+
+ for (i = 0; i < VHOST_KERNEL_MAX_QUEUES; ++i) {
+ if (internal->vhostfds[i] < 0)
+ continue;
+
+ ret = ioctl(internal->vhostfds[i], req_kernel, arg);
+ if (ret < 0)
+ break;
+ }
+
+ if (!ret && req_kernel == VHOST_SET_FEATURES)
+ internal->features = *((uint64_t *)arg);
+
+ /* with tap as the backend, all these features are supported but not
+ * claimed by vhost-net, so we add them back when reporting to upper
+ * layer
+ */
+ if (!ret && req_kernel == VHOST_GET_FEATURES)
+ *((uint64_t *)arg) |= guest_offloads_mask;
+
+ if (vm)
+ free(vm);
+
+ return ret;
+}
+
+/**
+ * Set up environment to talk with a vhost kernel backend.
+ * @param path
+ * - The path to vhost net (kernel) character file.
+ *
+ * @return
+ * - (-1) if fail to set up;
+ * - (>=0) if successful.
+ */
+static int
+vhost_kernel_setup(struct vhost_internal *internal, const char *path)
+{
+ int vhostfd;
+ uint32_t q;
+ uint32_t queue_pairs = 1;
+
+ for (q = 0; q < queue_pairs; ++q) {
+ vhostfd = open(path, O_RDWR);
+ if (vhostfd < 0) {
+ PMD_DRV_LOG(ERR, "fail to open %s, %s",
+ path, strerror(errno));
+ return -1;
+ }
+
+ internal->vhostfds[q] = vhostfd;
+ }
+
+ return 0;
+}
+
+static int
+_vhost_kernel_enable_queue_pair(int vhostfd, int tapfd)
+{
+ struct vhost_vring_file f;
+
+ f.fd = tapfd;
+ f.index = 0;
+ if (ioctl(vhostfd, VHOST_NET_SET_BACKEND, &f) < 0) {
+ PMD_DRV_LOG(ERR, "VHOST_NET_SET_BACKEND fails, %s",
+ strerror(errno));
+ return -1;
+ }
+
+ f.index = 1;
+ if (ioctl(vhostfd, VHOST_NET_SET_BACKEND, &f) < 0) {
+ PMD_DRV_LOG(ERR, "VHOST_NET_SET_BACKEND fails, %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+vhost_kernel_enable_queue_pair(struct vhost_internal *internal,
+ uint16_t pair_idx,
+ int enable)
+{
+ unsigned int offload =
+ TUN_F_CSUM |
+ TUN_F_TSO4 |
+ TUN_F_TSO6 |
+ TUN_F_TSO_ECN |
+ TUN_F_UFO;
+ unsigned int features;
+ int sndbuf = TUN_DEF_SNDBUF;
+ struct ifreq ifr;
+ int hdr_size;
+ int vhostfd;
+ int tapfd;
+ int req_mq;
+
+
+ vhostfd = internal->vhostfds[pair_idx];
+
+ if (!enable) {
+ if (internal->tapfds[pair_idx]) {
+ close(internal->tapfds[pair_idx]);
+ internal->tapfds[pair_idx] = -1;
+ }
+ return _vhost_kernel_enable_queue_pair(vhostfd, -1);
+ }
+
+ if ((internal->features & (1ULL << VIRTIO_NET_F_MRG_RXBUF)) ||
+ (internal->features & (1ULL << VIRTIO_F_VERSION_1)))
+ hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ else
+ hdr_size = sizeof(struct virtio_net_hdr);
+
+ req_mq = !!(internal->features & (1ULL << VIRTIO_NET_F_MQ));
+
+ /* TODO:
+ * 1. get/set offload capability, tap_probe_has_ufo, tap_fd_set_offload
+ * 2. verify we can get/set vnet_hdr_len, tap_probe_vnet_hdr_len
+ * 3. get number of memory regions from vhost module parameter
+ * max_mem_regions, supported in newer version linux kernel
+ */
+ tapfd = open(PATH_NET_TUN, O_RDWR);
+ if (tapfd < 0) {
+ PMD_DRV_LOG(ERR, "fail to open %s: %s",
+ PATH_NET_TUN, strerror(errno));
+ return -1;
+ }
+
+ /* Construct ifr */
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+
+ if (ioctl(tapfd, TUNGETFEATURES, &features) == -1) {
+ PMD_DRV_LOG(ERR, "TUNGETFEATURES failed: %s", strerror(errno));
+ goto error;
+ }
+ if (features & IFF_ONE_QUEUE)
+ ifr.ifr_flags |= IFF_ONE_QUEUE;
+
+ /* Let tap instead of vhost-net handle vnet header, as the latter does
+ * not support offloading. And in this case, we should not set feature
+ * bit VHOST_NET_F_VIRTIO_NET_HDR.
+ */
+ if (features & IFF_VNET_HDR) {
+ ifr.ifr_flags |= IFF_VNET_HDR;
+ } else {
+ PMD_DRV_LOG(ERR, "TAP does not support IFF_VNET_HDR");
+ goto error;
+ }
+
+ if (req_mq) {
+ if (features & IFF_MULTI_QUEUE)
+ ifr.ifr_flags |= IFF_MULTI_QUEUE;
+ else {
+ PMD_DRV_LOG(ERR, "multiqueue not supported by kernel");
+ goto error;
+ }
+ }
+
+ if (internal->ifname)
+ strncpy(ifr.ifr_name, internal->ifname, IFNAMSIZ);
+ else
+ strncpy(ifr.ifr_name, "tap%d", IFNAMSIZ);
+ if (ioctl(tapfd, TUNSETIFF, (void *)&ifr) == -1) {
+ PMD_DRV_LOG(ERR, "TUNSETIFF failed: %s", strerror(errno));
+ goto error;
+ }
+
+ fcntl(tapfd, F_SETFL, O_NONBLOCK);
+
+ if (ioctl(tapfd, TUNSETVNETHDRSZ, &hdr_size) < 0) {
+ PMD_DRV_LOG(ERR, "TUNSETVNETHDRSZ failed: %s", strerror(errno));
+ goto error;
+ }
+
+ if (ioctl(tapfd, TUNSETSNDBUF, &sndbuf) < 0) {
+ PMD_DRV_LOG(ERR, "TUNSETSNDBUF failed: %s", strerror(errno));
+ goto error;
+ }
+
+ if (_vhost_kernel_enable_queue_pair(vhostfd, tapfd) < 0)
+ goto error;
+
+ /* Only try best to set offload */
+ if (ioctl(tapfd, TUNSETOFFLOAD, offload) != 0)
+ PMD_DRV_LOG(ERR, "TUNSETOFFLOAD ioctl() failed: %s",
+ strerror(errno));
+
+ internal->tapfds[pair_idx] = tapfd;
+ if (!internal->ifname)
+ internal->ifname = strdup(ifr.ifr_name);
+
+ return 0;
+error:
+ return -1;
+}
+
+struct vhost_ops vhost_ops_kernel = {
+ .setup = vhost_kernel_setup,
+ .control = vhost_kernel_ioctl,
+ .enable_qp = vhost_kernel_enable_queue_pair
+};
--
2.7.4
^ permalink raw reply related
* [PATCH 3/3] net/virtio_user: fix wrongly set features
From: Jianfeng Tan @ 2016-12-02 14:31 UTC (permalink / raw)
To: dev; +Cc: yuanhan.liu, ferruh.yigit, cunming.liang, Jianfeng Tan
In-Reply-To: <1480689075-66977-1-git-send-email-jianfeng.tan@intel.com>
Before the commit 86d59b21468a ("net/virtio: support LRO"), features
in virtio PMD, is decided and properly set at device initialization
and will not be changed. But afterward, features could be changed in
virtio_dev_configure(), and will be re-negotiated if it's changed.
In virtio_user, host features is obtained at device initialization
only once, but we did not store it. So the added feature bits in
re-negotiation will fail.
Fixes: e9efa4d93821 ("net/virtio-user: add new virtual PCI driver")
Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
---
drivers/net/virtio/virtio_user/virtio_user_dev.c | 2 +-
drivers/net/virtio/virtio_user/virtio_user_dev.h | 1 +
drivers/net/virtio/virtio_user_ethdev.c | 4 ++--
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.c b/drivers/net/virtio/virtio_user/virtio_user_dev.c
index 3aef5f6..a9157a9 100644
--- a/drivers/net/virtio/virtio_user/virtio_user_dev.c
+++ b/drivers/net/virtio/virtio_user/virtio_user_dev.c
@@ -224,7 +224,7 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues,
}
if (vhost_call(dev->vid, VHOST_USER_GET_FEATURES,
- &dev->features) < 0) {
+ &dev->host_features) < 0) {
PMD_INIT_LOG(ERR, "get_features failed: %s", strerror(errno));
return -1;
}
diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.h b/drivers/net/virtio/virtio_user/virtio_user_dev.h
index 80efb6e..d219432 100644
--- a/drivers/net/virtio/virtio_user/virtio_user_dev.h
+++ b/drivers/net/virtio/virtio_user/virtio_user_dev.h
@@ -47,6 +47,7 @@ struct virtio_user_dev {
uint32_t queue_pairs;
uint32_t queue_size;
uint64_t features;
+ uint64_t host_features;
uint8_t status;
uint8_t mac_addr[ETHER_ADDR_LEN];
char path[PATH_MAX];
diff --git a/drivers/net/virtio/virtio_user_ethdev.c b/drivers/net/virtio/virtio_user_ethdev.c
index 406beea..cfe2bfc 100644
--- a/drivers/net/virtio/virtio_user_ethdev.c
+++ b/drivers/net/virtio/virtio_user_ethdev.c
@@ -117,7 +117,7 @@ virtio_user_get_features(struct virtio_hw *hw)
{
struct virtio_user_dev *dev = virtio_user_get_dev(hw);
- return dev->features;
+ return dev->host_features;
}
static void
@@ -125,7 +125,7 @@ virtio_user_set_features(struct virtio_hw *hw, uint64_t features)
{
struct virtio_user_dev *dev = virtio_user_get_dev(hw);
- dev->features = features;
+ dev->features = features & dev->host_features;
}
static uint8_t
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] Scheduler: add driver for scheduler crypto pmd
From: Thomas Monjalon @ 2016-12-02 14:31 UTC (permalink / raw)
To: Fan Zhang; +Cc: dev, declan.doherty
In-Reply-To: <1480688123-39494-1-git-send-email-roy.fan.zhang@intel.com>
2016-12-02 14:15, Fan Zhang:
> This patch provides the initial implementation of the scheduler poll mode
> driver using DPDK cryptodev framework.
>
> Scheduler PMD is used to schedule and enqueue the crypto ops to the
> hardware and/or software crypto devices attached to it (slaves). The
> dequeue operation from the slave(s), and the possible dequeued crypto op
> reordering, are then carried out by the scheduler.
>
> The scheduler PMD can be used to fill the throughput gap between the
> physical core and the existing cryptodevs to increase the overall
> performance. For example, if a physical core has higher crypto op
> processing rate than a cryptodev, the scheduler PMD can be introduced to
> attach more than one cryptodevs.
>
> This initial implementation is limited to supporting the following
> scheduling modes:
>
> - CRYPTO_SCHED_SW_ROUND_ROBIN_MODE (round robin amongst attached software
> slave cryptodevs, to set this mode, the scheduler should have been
> attached 1 or more software cryptodevs.
>
> - CRYPTO_SCHED_HW_ROUND_ROBIN_MODE (round robin amongst attached hardware
> slave cryptodevs (QAT), to set this mode, the scheduler should have
> been attached 1 or more QATs.
Could it be implemented on top of the eventdev API?
^ permalink raw reply
* Re: [PATCH 00/31] Support VFD and DPDK PF + kernel VF on i40e
From: Thomas Monjalon @ 2016-12-02 14:33 UTC (permalink / raw)
To: Iremonger, Bernard; +Cc: Lu, Wenzhuo, Yigit, Ferruh, dev
In-Reply-To: <8CEF83825BEC744B83065625E567D7C21A0B3CD1@IRSMSX108.ger.corp.intel.com>
2016-12-02 14:25, Iremonger, Bernard:
> Hi Thomas,
>
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> >
> > Do you agree to copy the remaining VF-specific functions from the generic
> > ethdev API to ixgbe in 17.02?
> > After a deprecation notice, we could remove them from the generic API in
> > 17.05.
> > So we will have a consistent status in 17.05 regarding VF functions.
> >
> > After some time (and experience) we will be able to discuss wether we need
> > something more to access to these specific features.
>
> I had intended to copy the remaining VF-specific functions from the generic ethdev API to ixgbe in 17.02 and a deprecation notice was sent in 16.11.
>
> This work was parked in order work on the VF-specfic functionsfor the i40e. Is it ok to submit patches for this work after the V1 deadline (today)?
Yes, it is a kind of cleanup and it has been discussed earlier.
So yes you can submit it later. Sooner is better though :)
Thanks
^ permalink raw reply
* Re: [PATCH 0/3] virtio_user as an alternative exception path
From: Thomas Monjalon @ 2016-12-02 14:44 UTC (permalink / raw)
To: Jianfeng Tan; +Cc: dev, yuanhan.liu, ferruh.yigit, cunming.liang
In-Reply-To: <1480689075-66977-1-git-send-email-jianfeng.tan@intel.com>
2016-12-02 14:31, Jianfeng Tan:
> In v16.07, we upstreamed a virtual device, virtio_user (with vhost-user
> as the backend). The path to go with a vhost-kernel backend has been
> dropped for bad performance comparing to vhost-user and code simplicity.
>
> But after a second thought, virtio_user + vhost-kernel is a good
> candidate as an exceptional path, such as KNI, which exchanges packets
> with kernel networking stack.
> - maintenance: vhost-net (kernel) is upstreamed and extensively used
> kernel module. We don't need any out-of-tree module like KNI.
> - performance: as with KNI, this solution would use one or more
> kthreads to send/receive packets from user space DPDK applications,
> which has little impact on user space polling thread (except that
> it might enter into kernel space to wake up those kthreads if
> necessary.
> - features: vhost-net is born to be a networking solution, which has
> lots of networking related featuers, like multi queue, tso, multi-seg
> mbuf, etc.
That's a really interesting trial.
Have I already said that I don't like KNI? ;)
> Known issues for current version:
> - Multiqueue not supported yet.
> - Offloading is completely enabled yet; to enhance, we will translate
Is a "not" missing in this sentence?
> the virtio header info into mbuf metadata when receiving packets
> from kernel; and translate mbuf metadata info into virtio header
> when sending packets to kernel.
So what is the ambition for 17.02?
Do you think it could be integrated?
^ permalink raw reply
* [PATCH 0/2] Elastic Flow Distributor
From: Pablo de Lara @ 2016-12-02 14:52 UTC (permalink / raw)
To: dev; +Cc: Pablo de Lara
EFD is a distributor library that uses perfect hashing to determine a
target/value for a given incoming flow key. It has the following advantages:
first, because it uses perfect hashing it does not store the key itself and
hence lookup performance is not dependent on the key size. Second, the
target/value can be any arbitrary value hence the system designer and/or
operator can better optimize service rates and inter-cluster network traffic
locating. Third, since the storage requirement is much smaller than a
hash-based flow table (i.e. better fit for CPU cache), EFD can scale to millions
of flow keys. Finally, with current optimized library implementation performance
is fully scalable with number of CPU cores.
The basic idea of EFD is when a given key is to be inserted, a family of hash
functions is searched until the correct hash function that maps the input key to
the correct value is found. However, rather than explicitly storing all keys and
their associated values, EFD stores only indices of hash functions that map keys
to values, and thereby consumes much less space than conventional flow-based
tables. The lookup operation is very simple, similar to computational-based
scheme, given an input key the lookup operation is reduced to hashing that key
with the correct hash function.
Intuitively, finding a hash function that maps each of a large number (millions)
of input keys to the correct output value is effectively impossible, as a result
EFD, breaks the problem into smaller pieces (divide and conquer). EFD divides
the entire input key set into many small groups. Each group consists of
approximately 20-28 keys (a configurable parameter for the library), then, for
each small group, a brute force search to find a hash function that produces the
correct outputs for each key in the group.
It should be mentioned that since in the online lookup table for EFD doesn’t
store the key itself, the size of the EFD table is independent of the key size
and hence EFD lookup performance which is almost constant irrespective of the
length of the key which is a highly desirable feature especially for longer
keys.
Library code is included in the patch, plus an sample application that shows
how the library can be used.
RFC for this library was already sent:
http://dpdk.org/ml/archives/dev/2016-October/049238.html
For more information on the library, check out the following document:
https://github.com/pablodelara/perfect_hash_flow_distributor/blob/master/EFD_description.pdf
Pablo de Lara (2):
efd: new Elastic Flow Distributor library
examples/flow_distributor: sample app to demonstrate EFD usage
config/common_base | 5 +
examples/Makefile | 1 +
examples/flow_distributor/Makefile | 44 +
examples/flow_distributor/distributor/Makefile | 57 ++
examples/flow_distributor/distributor/args.c | 200 ++++
examples/flow_distributor/distributor/args.h | 39 +
examples/flow_distributor/distributor/init.c | 371 ++++++++
examples/flow_distributor/distributor/init.h | 76 ++
examples/flow_distributor/distributor/main.c | 362 +++++++
examples/flow_distributor/node/Makefile | 48 +
examples/flow_distributor/node/node.c | 417 ++++++++
examples/flow_distributor/shared/common.h | 99 ++
lib/Makefile | 1 +
lib/librte_eal/common/include/rte_log.h | 1 +
lib/librte_efd/Makefile | 56 ++
lib/librte_efd/rte_efd.c | 1203 ++++++++++++++++++++++++
lib/librte_efd/rte_efd.h | 312 ++++++
lib/librte_efd/rte_efd_version.map | 12 +
mk/rte.app.mk | 1 +
19 files changed, 3305 insertions(+)
create mode 100644 examples/flow_distributor/Makefile
create mode 100644 examples/flow_distributor/distributor/Makefile
create mode 100644 examples/flow_distributor/distributor/args.c
create mode 100644 examples/flow_distributor/distributor/args.h
create mode 100644 examples/flow_distributor/distributor/init.c
create mode 100644 examples/flow_distributor/distributor/init.h
create mode 100644 examples/flow_distributor/distributor/main.c
create mode 100644 examples/flow_distributor/node/Makefile
create mode 100644 examples/flow_distributor/node/node.c
create mode 100644 examples/flow_distributor/shared/common.h
create mode 100644 lib/librte_efd/Makefile
create mode 100644 lib/librte_efd/rte_efd.c
create mode 100644 lib/librte_efd/rte_efd.h
create mode 100644 lib/librte_efd/rte_efd_version.map
--
2.7.4
^ permalink raw reply
* [PATCH 1/2] efd: new Elastic Flow Distributor library
From: Pablo de Lara @ 2016-12-02 14:52 UTC (permalink / raw)
To: dev; +Cc: Pablo de Lara
In-Reply-To: <1480690340-17652-1-git-send-email-pablo.de.lara.guarch@intel.com>
Elastic Flow Distributor (EFD) is a distributor library that uses
perfect hashing to determine a target/value for a given incoming flow key.
It has the following advantages:
- First, because it uses perfect hashing, it does not store the key itself and
hence lookup performance is not dependent on the key size.
- Second, the target/value can be any arbitrary value hence the system designer
and/or operator can better optimize service rates and inter-cluster
network traffic locating.
- Third, since the storage requirement is much smaller than a hash-based flow table
(i.e. better fit for CPU cache), EFD can scale to millions of flow keys.
Finally, with current optimized library implementation performance
is fully scalable with number of CPU cores.
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
config/common_base | 5 +
lib/Makefile | 1 +
lib/librte_eal/common/include/rte_log.h | 1 +
lib/librte_efd/Makefile | 56 ++
lib/librte_efd/rte_efd.c | 1203 +++++++++++++++++++++++++++++++
lib/librte_efd/rte_efd.h | 312 ++++++++
lib/librte_efd/rte_efd_version.map | 12 +
mk/rte.app.mk | 1 +
8 files changed, 1591 insertions(+)
create mode 100644 lib/librte_efd/Makefile
create mode 100644 lib/librte_efd/rte_efd.c
create mode 100644 lib/librte_efd/rte_efd.h
create mode 100644 lib/librte_efd/rte_efd_version.map
diff --git a/config/common_base b/config/common_base
index 4bff83a..376742a 100644
--- a/config/common_base
+++ b/config/common_base
@@ -458,6 +458,11 @@ CONFIG_RTE_LIBRTE_HASH=y
CONFIG_RTE_LIBRTE_HASH_DEBUG=n
#
+# Compile librte_efd
+#
+CONFIG_RTE_LIBRTE_EFD=y
+
+#
# Compile librte_jobstats
#
CONFIG_RTE_LIBRTE_JOBSTATS=y
diff --git a/lib/Makefile b/lib/Makefile
index 990f23a..9a41188 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -43,6 +43,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
+DIRS-$(CONFIG_RTE_LIBRTE_EFD) += librte_efd
DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm
DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl
DIRS-$(CONFIG_RTE_LIBRTE_NET) += librte_net
diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/common/include/rte_log.h
index 29f7d19..70e150d 100644
--- a/lib/librte_eal/common/include/rte_log.h
+++ b/lib/librte_eal/common/include/rte_log.h
@@ -79,6 +79,7 @@ extern struct rte_logs rte_logs;
#define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
#define RTE_LOGTYPE_MBUF 0x00010000 /**< Log related to mbuf. */
#define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to cryptodev. */
+#define RTE_LOGTYPE_EFD 0x00040000 /**< Log related to cryptodev. */
/* these log types can be used in an application */
#define RTE_LOGTYPE_USER1 0x01000000 /**< User-defined log type 1. */
diff --git a/lib/librte_efd/Makefile b/lib/librte_efd/Makefile
new file mode 100644
index 0000000..ae21bc7
--- /dev/null
+++ b/lib/librte_efd/Makefile
@@ -0,0 +1,56 @@
+# BSD LICENSE
+#
+# Copyright(c) 2016 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_efd.a
+
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
+CFLAGS += -D_GNU_SOURCE
+
+EXPORT_MAP := rte_efd_version.map
+
+LIBABIVER := 1
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_EFD) := rte_efd.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_EFD)-include := rte_efd.h
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_EFD) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_EFD) += lib/librte_mempool
+DEPDIRS-$(CONFIG_RTE_LIBRTE_EFD) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_EFD) += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_efd/rte_efd.c b/lib/librte_efd/rte_efd.c
new file mode 100644
index 0000000..0b8b51e
--- /dev/null
+++ b/lib/librte_efd/rte_efd.c
@@ -0,0 +1,1203 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <immintrin.h>
+#include <math.h>
+#include <sys/queue.h>
+
+#include <rte_log.h>
+#include <rte_eal_memconfig.h>
+#include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_prefetch.h>
+#include <rte_branch_prediction.h>
+
+#include "rte_efd.h"
+
+/** Hash function used to determine chunk_id and bin_id for a group */
+#define EFD_HASH(key) (efd_hash_internal((key), 0xbc9f1d34))
+/** Hash function used as constant component of perfect hash search */
+#define EFD_HASHFUNCA(key) (efd_hash_internal((key), 0xbc9f1d35))
+/** Hash function used as multiplicative component of perfect hash search */
+#define EFD_HASHFUNCB(key) (efd_hash_internal((key), 0xbc9f1d36))
+
+/*************************************************************************
+ * Fixed constants
+ *************************************************************************/
+
+/* These parameters are fixed by the efd_bin_to_group balancing table */
+#define EFD_CHUNK_NUM_GROUPS (64)
+#define EFD_CHUNK_NUM_BINS (256)
+#define EFD_CHUNK_NUM_BIN_TO_GROUP_SETS (EFD_CHUNK_NUM_BINS / EFD_CHUNK_NUM_GROUPS)
+
+/*
+ * Target number of rules that each chunk is created to handle.
+ * Used when initially allocating the table
+ */
+#define EFD_TARGET_CHUNK_NUM_RULES (EFD_CHUNK_NUM_GROUPS * EFD_TARGET_GROUP_NUM_RULES)
+
+/** This is fixed based on the bin_to_group permutation array */
+#define EFD_MAX_GROUP_NUM_BINS (16)
+
+/**
+ * The end of the chunks array needs some extra padding to ensure
+ * that vectorization over-reads on the last online chunk stay within
+allocated memory
+ */
+#define EFD_NUM_CHUNK_PADDING_BYTES (256)
+
+#define EFD_LOOKUPTBL_SHIFT (32 - 4)
+typedef uint16_t efd_lookuptbl_t;
+typedef uint16_t efd_hashfunc_t;
+
+TAILQ_HEAD(rte_efd_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_efd_tailq = {
+ .name = "RTE_EFD",
+};
+EAL_REGISTER_TAILQ(rte_efd_tailq);
+
+/** Internal permutation array used to shuffle bins into pseudorandom groups */
+const uint32_t efd_bin_to_group[EFD_CHUNK_NUM_BIN_TO_GROUP_SETS][EFD_CHUNK_NUM_BINS] = {
+ {
+ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
+ 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
+ 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
+ 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
+ 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
+ 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
+ 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
+ 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
+ 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
+ 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
+ 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
+ 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
+ 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
+ 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63
+ },
+ {
+ 34, 33, 48, 59, 0, 21, 36, 18, 9, 49, 54, 38, 51, 23, 31, 5,
+ 44, 23, 37, 52, 11, 4, 58, 20, 38, 40, 38, 22, 26, 28, 42, 6,
+ 46, 16, 31, 28, 46, 14, 60, 0, 35, 53, 16, 58, 16, 29, 39, 7,
+ 1, 54, 15, 11, 48, 3, 62, 9, 58, 5, 30, 43, 17, 7, 36, 34,
+ 6, 36, 2, 14, 10, 1, 47, 47, 20, 45, 62, 56, 34, 25, 39, 18,
+ 51, 41, 61, 25, 56, 40, 41, 37, 52, 35, 30, 57, 11, 42, 37, 27,
+ 54, 19, 26, 13, 48, 31, 46, 15, 12, 10, 16, 20, 43, 17, 12, 55,
+ 45, 18, 8, 41, 7, 31, 42, 63, 12, 14, 21, 57, 24, 40, 5, 41,
+ 13, 44, 23, 59, 25, 57, 52, 50, 62, 1, 2, 49, 32, 57, 26, 43,
+ 56, 60, 55, 5, 49, 6, 3, 50, 46, 39, 27, 33, 17, 4, 53, 13,
+ 2, 19, 36, 51, 63, 0, 22, 33, 59, 28, 29, 23, 45, 33, 53, 27,
+ 22, 21, 40, 56, 4, 18, 44, 47, 28, 17, 4, 50, 21, 62, 8, 39,
+ 0, 8, 15, 24, 29, 24, 9, 11, 48, 61, 35, 55, 43, 1, 54, 42,
+ 53, 60, 22, 3, 32, 52, 25, 8, 15, 60, 7, 55, 27, 63, 19, 10,
+ 63, 24, 61, 19, 12, 38, 6, 29, 13, 37, 10, 3, 45, 32, 32, 30,
+ 49, 61, 44, 14, 20, 58, 35, 30, 2, 26, 34, 51, 9, 59, 47, 50
+ },
+ {
+ 32, 35, 32, 34, 55, 5, 6, 23, 49, 11, 6, 23, 52, 37, 29, 54,
+ 55, 40, 63, 50, 29, 52, 61, 25, 12, 56, 39, 38, 29, 11, 46, 1,
+ 40, 11, 19, 56, 7, 28, 51, 16, 15, 48, 21, 51, 60, 31, 14, 22,
+ 41, 47, 59, 56, 53, 28, 58, 26, 43, 27, 41, 33, 24, 52, 44, 38,
+ 13, 59, 48, 51, 60, 15, 3, 30, 15, 0, 10, 62, 44, 14, 28, 51,
+ 38, 2, 41, 26, 25, 49, 10, 12, 55, 57, 27, 35, 19, 33, 0, 30,
+ 5, 36, 47, 53, 5, 53, 20, 43, 34, 37, 52, 41, 21, 63, 59, 9,
+ 24, 1, 45, 24, 39, 44, 45, 16, 9, 17, 7, 50, 57, 22, 18, 28,
+ 25, 45, 2, 40, 58, 15, 17, 3, 1, 27, 61, 39, 19, 0, 19, 21,
+ 57, 62, 54, 60, 54, 40, 48, 33, 36, 37, 4, 42, 1, 43, 58, 8,
+ 13, 42, 10, 56, 35, 22, 48, 61, 63, 10, 49, 9, 24, 9, 25, 57,
+ 33, 18, 13, 31, 42, 36, 36, 55, 30, 37, 53, 34, 59, 4, 4, 23,
+ 8, 16, 58, 14, 30, 11, 12, 63, 49, 62, 2, 39, 47, 22, 2, 60,
+ 18, 8, 46, 31, 6, 20, 32, 29, 46, 42, 20, 31, 32, 61, 34, 4,
+ 47, 26, 20, 43, 26, 21, 7, 3, 16, 35, 18, 44, 27, 62, 13, 23,
+ 6, 50, 12, 8, 45, 17, 3, 46, 50, 7, 14, 5, 17, 54, 38, 0
+ },
+ {
+ 29, 56, 5, 7, 54, 48, 23, 37, 35, 44, 52, 40, 33, 49, 60, 0,
+ 59, 51, 28, 12, 41, 26, 2, 23, 34, 5, 59, 40, 3, 19, 6, 26,
+ 35, 53, 45, 49, 29, 57, 28, 62, 58, 59, 19, 53, 59, 62, 6, 54,
+ 13, 15, 48, 50, 45, 21, 41, 12, 34, 40, 24, 56, 19, 21, 35, 18,
+ 55, 45, 9, 61, 47, 61, 19, 15, 16, 39, 17, 31, 3, 51, 21, 50,
+ 17, 25, 25, 11, 44, 16, 18, 28, 14, 2, 37, 61, 58, 27, 62, 4,
+ 14, 17, 1, 9, 46, 28, 37, 0, 53, 43, 57, 7, 57, 46, 21, 41,
+ 39, 14, 52, 60, 44, 53, 49, 60, 49, 63, 13, 11, 29, 1, 55, 47,
+ 55, 12, 60, 43, 54, 37, 13, 6, 42, 10, 36, 13, 9, 8, 34, 51,
+ 31, 32, 12, 7, 57, 2, 26, 14, 3, 30, 63, 3, 32, 1, 5, 11,
+ 27, 24, 26, 44, 31, 23, 56, 38, 62, 0, 40, 30, 6, 23, 38, 2,
+ 47, 5, 15, 27, 16, 10, 31, 25, 22, 63, 30, 25, 20, 33, 32, 50,
+ 29, 43, 55, 10, 50, 45, 56, 20, 4, 7, 27, 46, 11, 16, 22, 52,
+ 35, 20, 41, 54, 46, 33, 42, 18, 63, 8, 22, 58, 36, 4, 51, 42,
+ 38, 32, 38, 22, 17, 0, 47, 8, 48, 8, 48, 1, 61, 36, 33, 20,
+ 24, 39, 39, 18, 30, 36, 9, 43, 42, 24, 10, 58, 4, 15, 34, 52
+ },
+};
+
+/*************************************************************************
+ * Offline region structures
+ *************************************************************************/
+
+/** Online group containing number of rules, values, keys and their bins
+ * for EFD_MAX_GROUP_NUM_RULES rules.
+ */
+struct efd_offline_group_rules {
+ uint32_t num_rules;
+ /**< Sum of the number of rules in all bins assigned to this group. */
+
+ efd_key_t key[EFD_MAX_GROUP_NUM_RULES];
+ /**< Array with all keys of the group. */
+ efd_value_t value[EFD_MAX_GROUP_NUM_RULES];
+ /**< Array with all values of the keys of the group. */
+
+ uint8_t bin_id[EFD_MAX_GROUP_NUM_RULES];
+ /**< Stores the bin for each correspending key to
+ * avoid having to recompute it
+ */
+};
+
+/** Offline chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
+ * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
+ */
+struct efd_offline_chunk_rules {
+ uint16_t num_rules;
+ /**< Number of rules in the entire chunk; used to detect unbalanced groups */
+
+ struct efd_offline_group_rules group_rules[EFD_CHUNK_NUM_GROUPS];
+ /**< Array of all groups in the chunk. */
+};
+
+/*************************************************************************
+ * Online region structures
+ *************************************************************************/
+
+/** Online group containing values for EFD_MAX_GROUP_NUM_RULES rules. */
+struct efd_online_group_entry {
+ efd_hashfunc_t hash_idx[EFD_VALUE_NUM_BITS];
+ efd_lookuptbl_t lookup_table[EFD_VALUE_NUM_BITS];
+} __attribute__((__packed__));
+
+/**
+ * A single chunk record, containing EFD_TARGET_CHUNK_NUM_RULES rules.
+ * Those rules are split into EFD_CHUNK_NUM_GROUPS groups per chunk.
+ */
+struct efd_online_chunk {
+ uint8_t bin_choice_list[(EFD_CHUNK_NUM_BINS * 2 + 7) / 8];
+ /**< This is a packed indirection index into the 'groups' array.
+ * Each byte contains four two-bit values which index into
+ * the efd_bin_to_group array.
+ * The efd_bin_to_group array returns the index into the groups array
+ */
+
+ struct efd_online_group_entry groups[EFD_CHUNK_NUM_GROUPS];
+ /**< Array of all the groups in the chunk. */
+} __attribute__((__packed__));
+
+/**
+ * EFD table structure
+ */
+struct rte_efd_table {
+ char name[RTE_EFD_NAMESIZE]; /**< Name of the efd table. */
+
+ uint32_t max_num_rules;
+ /**< Static maximum number of entries the table was constructed to hold. */
+
+ uint32_t num_rules;
+ /**< Number of entries currently in the table . */
+
+ uint32_t num_chunks;
+ /**< Number of chunks in the table needed to support num_rules. */
+
+ uint32_t num_chunks_shift;
+ /**< Bits to shift to get chunk id, instead of dividing by num_chunk. */
+
+ struct efd_online_chunk *chunks[RTE_MAX_NUMA_NODES];
+ /**< Dynamic array of size num_chunks of chunk records. */
+
+ struct efd_offline_chunk_rules *offline_chunks;
+ /**< Dynamic array of size num_chunks of key-value pairs. */
+};
+
+
+/**
+ * Compute the hash of a key given a particular seed
+ *
+ * @param key
+ * key to hash
+ * @param seed
+ * seed for the hash function
+ *
+ * @return
+ * 32-bit hash
+ */
+static inline uint32_t
+efd_hash_internal(const efd_key_t *const key, const uint32_t seed)
+{
+ return (uint32_t)(rte_hash_crc(key->bytes, EFD_KEY_LEN, seed));
+}
+
+
+/**
+ * Computes the chunk ID for a given key hash
+ *
+ * @param table
+ * EFD table to reference
+ * @param hashed_key
+ * 32-bit key hash returned by EFD_HASH
+ *
+ * @return
+ * chunk ID containing this key hash
+ */
+static inline uint32_t
+efd_get_chunk_id(const struct rte_efd_table *const table,
+ const uint32_t hashed_key)
+{
+ return hashed_key & (table->num_chunks - 1);
+}
+
+/**
+ * Computes the bin ID for a given key hash
+ *
+ * @param table
+ * EFD table to reference
+ * @param hashed_key
+ * 32-bit key hash returned by EFD_HASH
+ *
+ * @return bin ID containing this key hash
+ */
+static inline uint32_t
+efd_get_bin_id(const struct rte_efd_table *const table,
+ const uint32_t hashed_key)
+{
+ return (hashed_key >> table->num_chunks_shift) & (EFD_CHUNK_NUM_BINS - 1);
+}
+
+/**
+ * Looks up the current permutation choice for a particular bin in the online table
+ *
+ * @param table
+ * EFD table to reference
+ * @param socket_id
+ * Socket ID to use to look up existing values (ideally caller's socket id)
+ * @param chunk_id
+ * Chunk ID of bin to look up
+ * @param bin_id
+ * Bin ID to look up
+ *
+ * @return
+ * Currently active permutation choice in the online table
+ */
+static inline uint8_t
+efd_get_choice(const struct rte_efd_table *const table,
+ const unsigned int socket_id,
+ const uint32_t chunk_id,
+ const uint32_t bin_id)
+{
+ struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
+
+ /*
+ * Grab the chunk (byte) that contains the choices
+ * for four neighboring bins.
+ */
+ uint8_t choice_chunk =
+ chunk->bin_choice_list[bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS];
+
+ /*
+ * Compute the offset into the chunk that contains
+ * the group_id lookup position
+ */
+ int offset = (bin_id & 0x3) * 2;
+
+ /* Extract from the byte just the desired lookup position */
+ return (uint8_t)((choice_chunk >> offset) & 0x3);
+}
+
+/**
+ * Compute the chunk_id and bin_id for a given key
+ *
+ * @param table
+ * EFD table to reference
+ * @param key
+ * Key to hash and find location of
+ * @param chunk_id
+ * Computed chunk ID
+ * @param bin_id
+ * Computed bin ID
+ *
+ */
+static inline void
+efd_compute_ids(const struct rte_efd_table *const table,
+ const efd_key_t *const key, uint32_t *const chunk_id,
+ uint32_t *const bin_id)
+{
+ /* Compute the position of the entry in the hash table */
+ uint32_t h = EFD_HASH(key);
+
+ /* Compute the chunk_id where that entry can be found */
+ *chunk_id = efd_get_chunk_id(table, h);
+
+ /*
+ * Compute the bin within that chunk where the entry
+ * can be found (0 - 255)
+ */
+ *bin_id = efd_get_bin_id(table, h);
+}
+
+/**
+ * Search for a hash function for a group that satisfies all group results
+ */
+static inline int
+efd_search_hash(const struct efd_offline_group_rules *const off_group,
+ struct efd_online_group_entry *const on_group)
+{
+ efd_hashfunc_t hash_idx;
+ efd_hashfunc_t start_hash_idx[EFD_VALUE_NUM_BITS];
+ efd_lookuptbl_t start_lookup_table[EFD_VALUE_NUM_BITS];
+
+ uint32_t i, j, rule_id;
+ uint32_t hash_val_a[EFD_MAX_GROUP_NUM_RULES];
+ uint32_t hash_val_b[EFD_MAX_GROUP_NUM_RULES];
+ uint32_t hash_val[EFD_MAX_GROUP_NUM_RULES];
+
+
+ rte_prefetch0(off_group->value);
+
+ /*
+ * Prepopulate the hash_val tables by running the two hash functions
+ * for each provided rule
+ */
+ for (i = 0; i < off_group->num_rules; i++) {
+ hash_val_b[i] = EFD_HASHFUNCB(&off_group->key[i]);
+ hash_val_a[i] = EFD_HASHFUNCA(&off_group->key[i]);
+ }
+
+ for (i = 0; i < EFD_VALUE_NUM_BITS; i++) {
+ hash_idx = on_group->hash_idx[i];
+ start_hash_idx[i] = hash_idx;
+
+ do {
+ efd_lookuptbl_t lookup_table = 0;
+ efd_lookuptbl_t lookup_table_complement = 0;
+
+ for (rule_id = 0; rule_id < off_group->num_rules; rule_id++)
+ hash_val[rule_id] = hash_val_a[rule_id] + (hash_idx *
+ hash_val_b[rule_id]);
+
+ /*
+ * The goal here is to find a hash function for this
+ * particular bit entry that meets the following criteria:
+ * The most significant bits of the hash result define a
+ * shift into the lookup table where the bit will be stored
+ */
+
+ /* Iterate over each provided rule */
+ for (rule_id = 0; rule_id < off_group->num_rules;
+ rule_id++) {
+ /*
+ * Use the few most significant bits (number based on
+ * EFD_LOOKUPTBL_SIZE) to see what position the
+ * expected bit should be set in the lookup_table
+ */
+ uint32_t bucket_idx = hash_val[rule_id] >>
+ EFD_LOOKUPTBL_SHIFT;
+
+ /*
+ * Get the current bit of interest.
+ * This only find an appropriate hash function
+ * for one bit at a time of the rule
+ */
+ efd_lookuptbl_t expected =
+ (off_group->value[rule_id] >> i) & 0x1;
+
+ /*
+ * Add the expected bit (if set) to a map
+ * (lookup_table). Also set its complement
+ * in lookup_table_complement
+ */
+ lookup_table |= expected << bucket_idx;
+ lookup_table_complement |= (1 - expected)
+ << bucket_idx;
+
+ /*
+ * If ever the hash function of two different
+ * elements result in different values at the
+ * same location in the lookup_table,
+ * the current hash_idx is not valid.
+ */
+ if (lookup_table & lookup_table_complement)
+ break;
+ }
+
+ /*
+ * Check if the previous loop completed without
+ * breaking early
+ */
+ if (rule_id == off_group->num_rules) {
+ /*
+ * Current hash function worked, store it
+ * for the current group
+ */
+ on_group->hash_idx[i] = hash_idx;
+ on_group->lookup_table[i] = lookup_table;
+
+ /*
+ * Make sure that the hash function has changed
+ * from the starting value
+ */
+ hash_idx = start_hash_idx[i] + 1;
+ break;
+ }
+ hash_idx++;
+
+ } while (hash_idx != start_hash_idx[i]);
+
+ /* Failed to find perfect hash for this group */
+ if (hash_idx == start_hash_idx[i]) {
+ /*
+ * Restore previous hash_idx and lookup_table
+ * for all value bits
+ */
+ for (j = 0; j < i; j++) {
+ on_group->hash_idx[j] = start_hash_idx[j];
+ on_group->lookup_table[j] = start_lookup_table[j];
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+struct rte_efd_table *
+rte_efd_create(const char *name, uint32_t max_num_rules,
+ uint8_t online_cpu_socket_bitmask,
+ uint8_t offline_cpu_socket)
+{
+ struct rte_efd_table *table = NULL;
+ uint32_t num_chunks, num_chunks_shift;
+ uint8_t socket_id;
+ struct rte_efd_list *efd_list = NULL;
+ struct rte_tailq_entry *te;
+ uint64_t offline_table_size;
+
+ efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
+
+ if (online_cpu_socket_bitmask == 0) {
+ RTE_LOG(ERR, EFD, "At least one CPU socket must be enabled "
+ "in the bitmask\n");
+ return NULL;
+ }
+
+ if (max_num_rules == 0) {
+ RTE_LOG(ERR, EFD, "Max num rules must be higher than 0\n");
+ return NULL;
+ }
+
+ /*
+ * Compute the minimum number of chunks (smallest power of 2)
+ * that can hold all of the rules
+ */
+ if (max_num_rules % EFD_TARGET_CHUNK_NUM_RULES == 0)
+ num_chunks = rte_align32pow2(max_num_rules /
+ EFD_TARGET_CHUNK_NUM_RULES);
+ else
+ num_chunks = rte_align32pow2((max_num_rules /
+ EFD_TARGET_CHUNK_NUM_RULES) + 1);
+
+ num_chunks_shift = log2(num_chunks);
+
+ rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
+
+ /*
+ * Guarantee there's no existing: this is normally already checked
+ * by ring creation above
+ */
+ TAILQ_FOREACH(te, efd_list, next) {
+ table = (struct rte_efd_table *) te->data;
+ if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
+ break;
+ }
+
+ table = NULL;
+ if (te != NULL) {
+ rte_errno = EEXIST;
+ te = NULL;
+ goto error_unlock_exit;
+ }
+
+ te = rte_zmalloc("EFD_TAILQ_ENTRY", sizeof(*te), 0);
+ if (te == NULL) {
+ RTE_LOG(ERR, EFD, "tailq entry allocation failed\n");
+ goto error_unlock_exit;
+ }
+
+ /* Create a new EFD table management structure */
+ table = (struct rte_efd_table *) rte_zmalloc_socket(NULL,
+ sizeof(struct rte_efd_table),
+ RTE_CACHE_LINE_SIZE,
+ offline_cpu_socket);
+ if (table == NULL) {
+ RTE_LOG(ERR, EFD, "Allocating EFD table management structure"
+ " on socket %u failed\n",
+ offline_cpu_socket);
+ goto error_unlock_exit;
+ }
+
+
+ RTE_LOG(DEBUG, EFD, "Allocated EFD table management structure "
+ "on socket %u\n", offline_cpu_socket);
+
+ table->max_num_rules = num_chunks * EFD_TARGET_CHUNK_NUM_RULES;
+ table->num_rules = 0;
+ table->num_chunks = num_chunks;
+ table->num_chunks_shift = num_chunks_shift;
+ snprintf(table->name, sizeof(table->name), "%s", name);
+
+ RTE_LOG(DEBUG, EFD, "Creating an EFD table with %u chunks,"
+ " which potentially supports %u entries\n",
+ num_chunks, table->max_num_rules);
+
+ /* Make sure all the allocatable table pointers are NULL initially */
+ for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++)
+ table->chunks[socket_id] = NULL;
+ table->offline_chunks = NULL;
+
+ /*
+ * Allocate one online table per socket specified
+ * in the user-supplied bitmask
+ */
+ uint64_t online_table_size = num_chunks * sizeof(struct efd_online_chunk) +
+ EFD_NUM_CHUNK_PADDING_BYTES;
+
+ for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++) {
+ if ((online_cpu_socket_bitmask >> socket_id) & 0x01) {
+ /*
+ * Allocate all of the EFD table chunks (the online portion)
+ * as a continuous block
+ */
+ table->chunks[socket_id] =
+ (struct efd_online_chunk *) rte_zmalloc_socket(NULL,
+ online_table_size,
+ RTE_CACHE_LINE_SIZE,
+ socket_id);
+ if (table->chunks[socket_id] == NULL) {
+ RTE_LOG(ERR, EFD,
+ "Allocating EFD online table on "
+ "socket %u failed\n",
+ socket_id);
+ goto error_unlock_exit;
+ }
+ RTE_LOG(DEBUG, EFD,
+ "Allocated EFD online table of size %lu bytes "
+ "(%.2f MB) on socket %u\n", online_table_size,
+ (float)online_table_size / (1024.0F * 1024.0F),
+ socket_id);
+ }
+ }
+
+ /*
+ * Allocate the EFD table offline portion (with the actual rules
+ * mapping keys to values) as a continuous block.
+ * This could be several gigabytes of memory.
+ */
+ offline_table_size = num_chunks * sizeof(struct efd_offline_chunk_rules);
+ table->offline_chunks =
+ (struct efd_offline_chunk_rules *) rte_zmalloc_socket(NULL,
+ offline_table_size,
+ RTE_CACHE_LINE_SIZE,
+ offline_cpu_socket);
+ if (table->offline_chunks == NULL) {
+ RTE_LOG(ERR, EFD, "Allocating EFD offline table on socket %u "
+ "failed\n", offline_cpu_socket);
+ goto error_unlock_exit;
+ }
+
+ RTE_LOG(DEBUG, EFD,
+ "Allocated EFD offline table of size %lu bytes "
+ " (%.2f MB) on socket %u\n", offline_table_size,
+ (float)offline_table_size / (1024.0F * 1024.0F),
+ offline_cpu_socket);
+
+ te->data = (void *) table;
+ TAILQ_INSERT_TAIL(efd_list, te, next);
+ rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+
+ return table;
+
+error_unlock_exit:
+ rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+ rte_efd_free(table);
+
+ return NULL;
+}
+
+struct rte_efd_table *
+rte_efd_find_existing(const char *name)
+{
+ struct rte_efd_table *table = NULL;
+ struct rte_tailq_entry *te;
+ struct rte_efd_list *efd_list;
+
+ efd_list = RTE_TAILQ_CAST(rte_efd_tailq.head, rte_efd_list);
+
+ rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
+ TAILQ_FOREACH(te, efd_list, next) {
+ table = (struct rte_efd_table *) te->data;
+ if (strncmp(name, table->name, RTE_EFD_NAMESIZE) == 0)
+ break;
+ }
+ rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
+
+ if (te == NULL) {
+ rte_errno = ENOENT;
+ return NULL;
+ }
+ return table;
+}
+
+void
+rte_efd_free(struct rte_efd_table *table)
+{
+ uint8_t socket_id;
+
+ if (table != NULL) {
+ for (socket_id = 0; socket_id < RTE_MAX_NUMA_NODES; socket_id++) {
+ if (table->chunks[socket_id] != NULL)
+ rte_free(table->chunks[socket_id]);
+ }
+
+ if (table->offline_chunks != NULL)
+ rte_free(table->offline_chunks);
+
+ rte_free(table);
+ }
+}
+
+/**
+ * Applies a previously computed table entry to the specified table for all
+ * socket-local copies of the online table.
+ * Intended to apply an update for only a single change
+ * to a key/value pair at a time
+ *
+ * @param table
+ * EFD table to reference
+ * @param socket_id
+ * Socket ID to use to lookup existing values (ideally caller's socket id)
+ * @param chunk_id
+ * Chunk index to update
+ * @param group_id
+ * Group index to update
+ * @param bin_id
+ * Bin within the group that this update affects
+ * @param new_bin_choice
+ * Newly chosen permutation which this bin should use - only lower 2 bits
+ * @param new_group_entry
+ * Previously computed updated chunk/group entry
+ */
+static inline void
+efd_apply_update(struct rte_efd_table *const table, const unsigned int socket_id,
+ const uint32_t chunk_id, const uint32_t group_id,
+ const uint32_t bin_id, const uint8_t new_bin_choice,
+ const struct efd_online_group_entry *const new_group_entry)
+{
+ int i;
+ struct efd_online_chunk *chunk = &table->chunks[socket_id][chunk_id];
+ uint8_t bin_index = bin_id / EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
+
+ /*
+ * Grab the current byte that contains the choices
+ * for four neighboring bins
+ */
+ uint8_t choice_chunk =
+ chunk->bin_choice_list[bin_index];
+
+
+ /* Compute the offset into the chunk that needs to be updated */
+ int offset = (bin_id & 0x3) * 2;
+
+ /* Zero the two bits of interest and set them to new_bin_choice */
+ choice_chunk = (choice_chunk & (~(0x03 << offset)))
+ | ((new_bin_choice & 0x03) << offset);
+
+ /* Update the online table with the new data across all sockets */
+ for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
+ if (table->chunks[i] != NULL) {
+ memcpy(&(table->chunks[i][chunk_id].groups[group_id]),
+ new_group_entry,
+ sizeof(struct efd_online_group_entry));
+ table->chunks[i][chunk_id].bin_choice_list[bin_index] =
+ choice_chunk;
+ }
+ }
+}
+
+
+/**
+ * Computes an updated table entry where the supplied key points to a new host.
+ * If no entry exists, one is inserted.
+ *
+ * This function does NOT modify the online table(s)
+ * This function DOES modify the offline table
+ *
+ * @param table
+ * EFD table to reference
+ * @param socket_id
+ * Socket ID to use to lookup existing values (ideally caller's socket id)
+ * @param key
+ * Key to insert
+ * @param value
+ * Value to associate with key
+ * @param chunk_id
+ * Chunk ID of the chunk that was modified
+ * @param group_id
+ * Group ID of the group that was modified
+ * @param bin_id
+ * Bin ID that was modified
+ * @param new_bin_choice
+ * Newly chosen permutation which this bin will use
+ * @param entry
+ * Newly computed online entry to apply later with efd_apply_update
+ *
+ * @return
+ * EFD_UPDATE_WARN_GROUP_FULL
+ * Operation is insert, and the last available space in the
+ * key's group was just used. Future inserts may fail as groups fill up.
+ * This operation was still successful, and entry contains a valid update
+ * EFD_UPDATE_FAILED
+ * Either the EFD failed to find a suitable perfect hash or the group was full
+ * This is a fatal error, and the table is now in an indeterminite state
+ * EFD_UPDATE_NO_CHANGE
+ * Operation resulted in no change to the table (same value already exists)
+ * 0
+ * Insert or update was successful, and the new efd_online_group_entry
+ * is stored in *entry
+ *
+ * @warning
+ * Note that entry will be UNCHANGED if the update has no effect, and thus any
+ * subsequent use of the entry content will likely be invalid
+ */
+static inline int
+efd_compute_update(struct rte_efd_table *const table, const unsigned int socket_id,
+ const efd_key_t *const key, const efd_value_t value,
+ uint32_t *const chunk_id, uint32_t *const group_id,
+ uint32_t *const bin_id, uint8_t *const new_bin_choice,
+ struct efd_online_group_entry *const entry)
+{
+ unsigned int i;
+ int ret;
+ int status = EXIT_SUCCESS;
+ int found = 0;
+
+ efd_compute_ids(table, key, chunk_id, bin_id);
+
+ struct efd_offline_chunk_rules *const chunk =
+ &table->offline_chunks[*chunk_id];
+ struct efd_offline_group_rules *new_group;
+ struct efd_offline_group_rules current_group_copy;
+ struct efd_offline_group_rules new_group_copy;
+
+ uint8_t current_choice = efd_get_choice(table, socket_id,
+ *chunk_id, *bin_id);
+ uint32_t current_group_id = efd_bin_to_group[current_choice][*bin_id];
+ struct efd_offline_group_rules *const current_group =
+ &chunk->group_rules[current_group_id];
+ uint8_t bin_size = 0;
+
+ /* Scan the current group and see if the key is already present */
+ for (i = 0; i < current_group->num_rules; i++) {
+ if (current_group->bin_id[i] == *bin_id)
+ bin_size++;
+
+ if (found == 0 && unlikely(memcmp(¤t_group->key[i],
+ key, EFD_KEY_LEN) == 0)) {
+ /* Key is already present */
+
+ /*
+ * If previous value is same as new value,
+ * no additional work is required
+ */
+ if (current_group->value[i] == value)
+ return EFD_UPDATE_NO_CHANGE;
+
+ /* Save the original group state, if update fails */
+ memcpy(¤t_group_copy, current_group,
+ sizeof(struct efd_offline_group_rules));
+ current_group->value[i] = value;
+ found = 1;
+ }
+ }
+
+ if (found == 0) {
+ /* Key does not exist. Insert the rule into the bin/group */
+ if (unlikely(current_group->num_rules >= EFD_MAX_GROUP_NUM_RULES)) {
+ RTE_LOG(ERR, EFD,
+ "Fatal: No room remaining for insert into "
+ "chunk %u group %u bin %u\n",
+ *chunk_id,
+ current_group_id, *bin_id);
+ return EFD_UPDATE_FAILED;
+ }
+ /* Save the original group state, if update fails */
+ memcpy(¤t_group_copy, current_group,
+ sizeof(struct efd_offline_group_rules));
+
+ if (unlikely(current_group->num_rules ==
+ (EFD_MAX_GROUP_NUM_RULES - 1))) {
+ RTE_LOG(INFO, EFD, "Warn: Insert into last "
+ "available slot in chunk %u "
+ "group %u bin %u\n", *chunk_id,
+ current_group_id, *bin_id);
+ status = EFD_UPDATE_WARN_GROUP_FULL;
+ }
+ memcpy(¤t_group->key[current_group->num_rules],
+ key, EFD_KEY_LEN);
+ current_group->value[current_group->num_rules] = value;
+ current_group->bin_id[current_group->num_rules] = *bin_id;
+ table->num_rules++;
+ current_group->num_rules++;
+ bin_size++;
+ }
+
+ /* Group need to be rebalanced when it starts to get loaded */
+ if (current_group->num_rules > EFD_MIN_BALANCED_NUM_RULES) {
+
+ /*
+ * Subtract the number of entries in the bin from
+ * the original group
+ */
+ current_group->num_rules -= bin_size;
+
+ /*
+ * Figure out which of the available groups that this bin
+ * can map to is the smallest (using the current group
+ * as baseline)
+ */
+ uint8_t smallest_choice = current_choice;
+ uint8_t smallest_size = current_group->num_rules;
+ uint32_t smallest_group_id = current_group_id;
+ unsigned char choice;
+
+ for (choice = 0; choice < EFD_CHUNK_NUM_BIN_TO_GROUP_SETS;
+ choice++) {
+ uint32_t test_group_id =
+ efd_bin_to_group[choice][*bin_id];
+ uint32_t num_rules =
+ chunk->group_rules[test_group_id].num_rules;
+ if (num_rules < smallest_size) {
+ smallest_choice = choice;
+ smallest_size = num_rules;
+ smallest_group_id = test_group_id;
+ }
+ }
+
+ *new_bin_choice = smallest_choice;
+ *group_id = smallest_group_id;
+ new_group = &chunk->group_rules[smallest_group_id];
+
+ if (smallest_group_id == current_group_id) {
+ new_group->num_rules += bin_size;
+ RTE_LOG(DEBUG, EFD, "chunk %u: Left bin %u (%u entries) "
+ "in group %u (%u entries)\n", *chunk_id,
+ *bin_id, bin_size, *group_id,
+ new_group->num_rules);
+ } else {
+ /*
+ * Remove the bin from the group it was previously
+ * assigned to and add it to the new group
+ */
+
+ RTE_LOG(DEBUG, EFD, "chunk %u: Moving bin %u (%u entries) "
+ "from group %u (%u entries) to %u "
+ "(%u entries)\n", *chunk_id, *bin_id,
+ bin_size, current_group_id,
+ current_group->num_rules + bin_size,
+ smallest_group_id,
+ new_group->num_rules + bin_size);
+
+ /* Save the original group state, if update fails */
+ memcpy(&new_group_copy, new_group,
+ sizeof(struct efd_offline_group_rules));
+
+ uint8_t empty_idx = 0;
+
+ for (i = 0; i < current_group->num_rules + bin_size; i++) {
+ /*
+ * Move keys that belong to the same bin
+ * to the new group
+ */
+ if (current_group->bin_id[i] == *bin_id) {
+ new_group->key[new_group->num_rules] =
+ current_group->key[i];
+ new_group->value[new_group->num_rules] =
+ current_group->value[i];
+ new_group->bin_id[new_group->num_rules] =
+ current_group->bin_id[i];
+ new_group->num_rules++;
+ } else {
+ if (i != empty_idx) {
+ /*
+ * Need to move this key towards
+ * the top of the array
+ */
+ current_group->key[empty_idx] =
+ current_group->key[i];
+ current_group->value[empty_idx] =
+ current_group->value[i];
+ current_group->bin_id[empty_idx] =
+ current_group->bin_id[i];
+ }
+ empty_idx++;
+ }
+
+ }
+ }
+ } else {
+ *new_bin_choice = current_choice;
+ *group_id = current_group_id;
+ new_group = current_group;
+ }
+
+ /*
+ * Recompute the hash function for the modified group,
+ * and return it to the caller
+ */
+ ret = efd_search_hash(new_group, entry);
+
+ if (ret != 0) {
+ RTE_LOG(ERR, EFD,
+ "Failed to find perfect hash for group "
+ "containing %u entries\n",
+ new_group->num_rules);
+ /* Restore table to the previous state */
+ if (new_group != current_group)
+ memcpy(new_group, &new_group_copy,
+ sizeof(struct efd_offline_group_rules));
+ memcpy(current_group, ¤t_group_copy,
+ sizeof(struct efd_offline_group_rules));
+
+ return EFD_UPDATE_FAILED;
+ }
+
+ return status;
+}
+
+int
+rte_efd_update(struct rte_efd_table *const table, const unsigned int socket_id,
+ const efd_key_t *const key,
+ const efd_value_t value)
+{
+ uint32_t chunk_id, group_id, bin_id;
+ uint8_t new_bin_choice;
+ struct efd_online_group_entry entry;
+
+ int status = efd_compute_update(table, socket_id, key, value,
+ &chunk_id, &group_id, &bin_id,
+ &new_bin_choice, &entry);
+
+ if (status == EFD_UPDATE_NO_CHANGE)
+ return EXIT_SUCCESS;
+
+ if (status != EXIT_SUCCESS)
+ return status;
+
+ efd_apply_update(table, socket_id, chunk_id, group_id, bin_id,
+ new_bin_choice, &entry);
+ return status;
+}
+
+int
+rte_efd_delete(struct rte_efd_table *const table, const unsigned int socket_id,
+ const efd_key_t *const key, efd_value_t *const prev_value)
+{
+ unsigned int i;
+ uint32_t chunk_id, bin_id;
+ uint8_t not_found = 1;
+
+ efd_compute_ids(table, key, &chunk_id, &bin_id);
+
+ struct efd_offline_chunk_rules *const chunk =
+ &table->offline_chunks[chunk_id];
+
+ uint8_t current_choice = efd_get_choice(table, socket_id,
+ chunk_id, bin_id);
+ uint32_t current_group_id = efd_bin_to_group[current_choice][bin_id];
+ struct efd_offline_group_rules *const current_group =
+ &chunk->group_rules[current_group_id];
+
+ /*
+ * Search the current group for the specified key.
+ * If it exists, remove it and re-pack the other values
+ */
+ for (i = 0; i < current_group->num_rules; i++) {
+ if (not_found) {
+ /* Found key that needs to be removed */
+ if (memcmp(¤t_group->key[i], key, EFD_KEY_LEN) == 0) {
+ /* Store previous value if requested by caller */
+ if (prev_value != NULL)
+ *prev_value = current_group->value[i];
+
+ not_found = 0;
+ }
+ } else {
+ /*
+ * If the desired key has been found,
+ * need to shift other values up one
+ */
+
+ /* Need to shift this entry back up one index */
+ current_group->key[i - 1] = current_group->key[i];
+ current_group->value[i - 1] = current_group->value[i];
+ current_group->bin_id[i - 1] = current_group->bin_id[i];
+ }
+ }
+
+ if (not_found == 0) {
+ table->num_rules--;
+ current_group->num_rules--;
+ }
+
+ return not_found;
+}
+
+
+#if (EFD_VALUE_NUM_BITS == 8 || EFD_VALUE_NUM_BITS == 16 || \
+ EFD_VALUE_NUM_BITS == 24 || EFD_VALUE_NUM_BITS == 32)
+#define EFD_LOAD_SI128(val) _mm_load_si128(val)
+#else
+#define EFD_LOAD_SI128(val) _mm_lddqu_si128(val)
+#endif
+
+static inline efd_value_t
+efd_lookup_internal(const struct efd_online_group_entry *const group,
+ const uint32_t hash_val_a, const uint32_t hash_val_b)
+{
+ efd_value_t value = 0;
+
+#if EFD_VALUE_NUM_BITS > 3 && defined(RTE_MACHINE_CPUFLAG_AVX2)
+ uint32_t byte_idx;
+
+ __m256i vhash_val_a = _mm256_set1_epi32(hash_val_a);
+ __m256i vhash_val_b = _mm256_set1_epi32(hash_val_b);
+
+ for (byte_idx = 0; byte_idx < EFD_VALUE_NUM_BITS; byte_idx += 8) {
+ __m256i vhash_idx =
+ _mm256_cvtepu16_epi32(EFD_LOAD_SI128((__m128i const *)
+ &group->hash_idx[byte_idx]));
+ __m256i vlookup_table = _mm256_cvtepu16_epi32(
+ EFD_LOAD_SI128((__m128i const *)
+ &group->lookup_table[byte_idx]));
+ __m256i vhash = _mm256_add_epi32(vhash_val_a,
+ _mm256_mullo_epi32(vhash_idx, vhash_val_b));
+ __m256i vbucket_idx = _mm256_srli_epi32(vhash, EFD_LOOKUPTBL_SHIFT);
+ __m256i vresult = _mm256_srlv_epi32(vlookup_table, vbucket_idx);
+
+ value |= (_mm256_movemask_ps((__m256)_mm256_slli_epi32(vresult, 31))
+ & ((1 << (EFD_VALUE_NUM_BITS - byte_idx)) - 1)) << byte_idx;
+ }
+#else
+ uint32_t bit;
+
+ for (bit = 0; bit < EFD_VALUE_NUM_BITS; bit++) {
+ value <<= 1;
+
+ uint32_t h = hash_val_a + (hash_val_b *
+ group->hash_idx[EFD_VALUE_NUM_BITS - bit - 1]);
+ uint16_t bucket_idx = h >> EFD_LOOKUPTBL_SHIFT;
+
+ value |= (group->lookup_table[EFD_VALUE_NUM_BITS - bit - 1] >>
+ bucket_idx) & 0x1;
+ }
+#endif
+
+ return value;
+}
+
+efd_value_t
+rte_efd_lookup(const struct rte_efd_table *const table, const unsigned int socket_id,
+ const efd_key_t *const key)
+{
+ uint32_t chunk_id, group_id, bin_id;
+ uint8_t bin_choice;
+ const struct efd_online_group_entry *group;
+ const struct efd_online_chunk *const chunks = table->chunks[socket_id];
+
+ /* Determine the chunk and group location for the given key */
+ efd_compute_ids(table, key, &chunk_id, &bin_id);
+ bin_choice = efd_get_choice(table, socket_id, chunk_id, bin_id);
+ group_id = efd_bin_to_group[bin_choice][bin_id];
+ group = &chunks[chunk_id].groups[group_id];
+
+ return efd_lookup_internal(group, EFD_HASHFUNCA(key), EFD_HASHFUNCB(key));
+}
+
+void rte_efd_lookup_bulk(const struct rte_efd_table *const table,
+ const unsigned int socket_id, const int num_keys,
+ const efd_key_t *const *const key_list,
+ efd_value_t *const value_list)
+{
+ int i;
+ uint32_t chunk_id_list[EFD_BURST_MAX];
+ uint32_t bin_id_list[EFD_BURST_MAX];
+ uint8_t bin_choice_list[EFD_BURST_MAX];
+ uint32_t group_id_list[EFD_BURST_MAX];
+ struct efd_online_group_entry *group;
+
+ struct efd_online_chunk *chunks = table->chunks[socket_id];
+
+ for (i = 0; i < num_keys; i++) {
+ efd_compute_ids(table, key_list[i], &chunk_id_list[i],
+ &bin_id_list[i]);
+ rte_prefetch0(&chunks[chunk_id_list[i]].bin_choice_list);
+ }
+
+ for (i = 0; i < num_keys; i++) {
+ bin_choice_list[i] = efd_get_choice(table, socket_id,
+ chunk_id_list[i], bin_id_list[i]);
+ group_id_list[i] =
+ efd_bin_to_group[bin_choice_list[i]][bin_id_list[i]];
+ group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
+ rte_prefetch0(group);
+ }
+
+ for (i = 0; i < num_keys; i++) {
+ group = &chunks[chunk_id_list[i]].groups[group_id_list[i]];
+ value_list[i] = efd_lookup_internal(group,
+ EFD_HASHFUNCA(key_list[i]),
+ EFD_HASHFUNCB(key_list[i]));
+ }
+}
+
diff --git a/lib/librte_efd/rte_efd.h b/lib/librte_efd/rte_efd.h
new file mode 100644
index 0000000..ede5acf
--- /dev/null
+++ b/lib/librte_efd/rte_efd.h
@@ -0,0 +1,312 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LIBEFD_H__
+#define __LIBEFD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_hash_crc.h>
+#include "rte_lcore.h"
+
+/*************************************************************************
+ * User selectable constants
+ *************************************************************************/
+
+/*
+ * If possible, best lookup performance will be achieved by ensuring that
+ * the entire table fits in the L3 cache.
+ *
+ * Some formulas for calculating various sizes are listed below:
+ *
+ * # of chunks =
+ * 2 ^ (ceiling(log2((requested # of rules) /
+ * (EFD_CHUNK_NUM_GROUPS * EFD_TARGET_GROUP_NUM_RULES))))
+ *
+ * Target # of rules = (# of chunks) * EFD_CHUNK_NUM_GROUPS *
+ * EFD_TARGET_GROUP_NUM_RULES
+ *
+ * Group Size (in bytes) = 4 (per value bit)
+ *
+ * Table size (in bytes) = EFD_VALUE_NUM_BITS * (# of chunks) *
+ * EFD_CHUNK_NUM_GROUPS * (group size)
+ */
+
+/**
+ * !!! This parameter should be adjusted for your application !!!
+ *
+ * This parameter adjusts the number of bits of value that can be
+ * stored in the table.
+ * For example, setting the number of bits to 3 will allow storing 8 values
+ * in the table (between 0 and 7).
+ *
+ * This number directly affects the performance of both lookups and insertion.
+ * In general, performance decreases as more bits are stored in the table.
+ *
+ * This number is directly proportional to the size of the online region
+ * used for lookups.
+ *
+ * Note that due to the way the CPU operates on memory, best lookup performance
+ * will be achieved when EFD_VALUE_NUM_BITS is a multiple of 8.
+ * These values align the hash indexes on 16-byte boundaries.
+ * The greatest performance drop is moving from 8->9 bits, 16->17 bits, etc.
+ *
+ * This value must be between 1 and 32
+ */
+#ifndef EFD_VALUE_NUM_BITS
+#define EFD_VALUE_NUM_BITS (8)
+#endif
+
+/**
+ * !!! This parameter should be adjusted for your application !!!
+ *
+ * This parameter adjusts the size of the keys stored in the table (in bytes).
+ * There are no restrictions around valid key sizes, and larger keys
+ * do not change the size of the online table used for lookups.
+ */
+#ifndef EFD_KEY_LEN
+#define EFD_KEY_LEN (4)
+#endif
+
+/*
+ * EFD_TARGET_GROUP_NUM_RULES:
+ * Adjusts how many groups/chunks are allocated at table creation time
+ * to support the requested number of rules. Higher values pack entries
+ * more tightly in memory, resulting in a smaller memory footprint
+ * for the online table.
+ * This comes at the cost of lower insert/update performance.
+ *
+ * EFD_MAX_GROUP_NUM_RULES:
+ * This adjusts the amount of offline memory allocated to store key/value
+ * pairs for the table. The recommended numbers are upper-bounds for
+ * this parameter
+ * - any higher and it becomes very unlikely that a perfect hash function
+ * can be found for that group size. This value should be at
+ * least 40% larger than EFD_TARGET_GROUP_NUM_RULES
+ *
+ * Recommended values for various lookuptable and hashfunc sizes are:
+ *
+ * HASH_FUNC_SIZE = 16, LOOKUPTBL_SIZE = 16:
+ * EFD_TARGET_GROUP_NUM_RULES = 22
+ * EFD_MAX_GROUP_NUM_RULES = 28
+ */
+#define EFD_TARGET_GROUP_NUM_RULES (22)
+#define EFD_MAX_GROUP_NUM_RULES (28)
+
+#define EFD_MIN_BALANCED_NUM_RULES 5
+
+/**
+ * Maximum number of keys that can be looked up in one call to efd_lookup_bulk
+ */
+#ifndef EFD_BURST_MAX
+#define EFD_BURST_MAX (32)
+#endif
+
+/** Maximum number of characters in efd name.*/
+#define RTE_EFD_NAMESIZE 32
+
+#if (EFD_VALUE_NUM_BITS > 0 && EFD_VALUE_NUM_BITS <= 8)
+typedef uint8_t efd_value_t;
+#elif (EFD_VALUE_NUM_BITS > 8 && EFD_VALUE_NUM_BITS <= 16)
+typedef uint16_t efd_value_t;
+#elif (EFD_VALUE_NUM_BITS > 16 && EFD_VALUE_NUM_BITS <= 32)
+typedef uint32_t efd_value_t;
+#else
+#error("EFD_VALUE_NUM_BITS must be in the range [1:32]")
+#endif
+
+#if (EFD_KEY_LEN <= 0)
+#error("EFD_KEY_LEN must be an integer greater than 0")
+#endif
+
+/* Variable size keys */
+typedef struct {
+ uint8_t bytes[EFD_KEY_LEN];
+} efd_key_t;
+
+/**
+ * Creates an EFD table with a single offline region and multiple per-socket
+ * internally-managed copies of the online table used for lookups
+ *
+ * @param name
+ * EFD table name
+ * @param max_num_rules
+ * Minimum number of rules the table should be sized to hold.
+ * Will be rounded up to the next smallest valid table size
+ * @param online_cpu_socket_bitmask
+ * Bitmask specifying which sockets should get a copy of the online table.
+ * LSB = socket 0, etc.
+ * @param offline_cpu_socket
+ * Identifies the socket where the offline table will be allocated
+ * (and most efficiently accessed in the case of updates/insertions)
+ *
+ * @return
+ * EFD table, or NULL if table allocation failed or the bitmask is invalid
+ */
+struct rte_efd_table *
+rte_efd_create(const char *name, uint32_t max_num_rules,
+ uint8_t online_cpu_socket_bitmask, uint8_t offline_cpu_socket);
+
+/**
+ * Releases the resources from an EFD table
+ *
+ * @param table
+ * Table to free
+ */
+void
+rte_efd_free(struct rte_efd_table *table);
+
+/**
+ * Find an existing EFD table object and return a pointer to it.
+ *
+ * @param name
+ * Name of the EFD table as passed to rte_hash_create()
+ * @return
+ * Pointer to EFD table or NULL if object not found
+ * with rte_errno set appropriately. Possible rte_errno values include:
+ * - ENOENT - value not available for return
+ */
+struct rte_efd_table*
+rte_efd_find_existing(const char *name);
+
+#define EFD_UPDATE_WARN_GROUP_FULL (1)
+#define EFD_UPDATE_NO_CHANGE (2)
+#define EFD_UPDATE_FAILED (3)
+
+/**
+ * Computes an updated table entry for the supplied key/value pair.
+ * The update is then immediately applied to the provided table and
+ * all socket-local copies of the chunks are updated.
+ *
+ * @param table
+ * EFD table to reference
+ * @param socket_id
+ * Socket ID to use to lookup existing value (ideally caller's socket id)
+ * @param key
+ * EFD table key to modify
+ * @param value
+ * Value to associate with the key
+ *
+ * @return
+ * EFD_UPDATE_WARN_GROUP_FULL
+ * Operation is insert, and the last available space in the
+ * key's group was just used
+ * Future inserts may fail as groups fill up
+ * This operation was still successful, and entry contains a valid update
+ * EFD_UPDATE_FAILED
+ * Either the EFD failed to find a suitable perfect hash or the group was full
+ * This is a fatal error, and the table is now in an indeterminite state
+ * EFD_UPDATE_NO_CHANGE
+ * Operation resulted in no change to the table (same value already exists)
+ * 0 - success
+ */
+int
+rte_efd_update(struct rte_efd_table *table, unsigned int socket_id,
+ const efd_key_t *key, efd_value_t value);
+
+/**
+ * Removes any value currently associated with the specified key from the table
+ *
+ * @param table
+ * EFD table to reference
+ * @param socket_id
+ * Socket ID to use to lookup existing value (ideally caller's socket id)
+ * @param key
+ * EFD table key to delete
+ * @param prev_value
+ * If not NULL, will store the previous value here before deleting it
+ *
+ * @return
+ * 0 - successfully found and deleted the key
+ * nonzero otherwise
+ */
+int
+rte_efd_delete(struct rte_efd_table *table, unsigned int socket_id,
+ const efd_key_t *key, efd_value_t *prev_value);
+
+/**
+ * Looks up the value associated with a key
+ *
+ * NOTE: Lookups will *always* succeed - this is a property of
+ * using a perfect hash table.
+ * If the specified key was never inserted, a pseudorandom answer will be returned.
+ * There is no way to know based on the lookup if the key was ever inserted
+ * originally, so this must be tracked elsewhere.
+ *
+ * @param table
+ * EFD table to reference
+ * @param socket_id
+ * Socket ID to use to lookup existing value (ideally caller's socket id)
+ * @param key
+ * EFD table key to look up
+ *
+ * @return
+ * Value associated with the key, or random junk if they key was never inserted
+ */
+efd_value_t
+rte_efd_lookup(const struct rte_efd_table *table, unsigned int socket_id,
+ const efd_key_t *key);
+
+/**
+ * Looks up the value associated with several keys.
+ *
+ * NOTE: Lookups will *always* succeed - this is a property of
+ * using a perfect hash table.
+ * If the specified key was never inserted, a pseudorandom answer will be returned.
+ * There is no way to know based on the lookup if the key was ever inserted
+ * originally, so this must be tracked elsewhere.
+ *
+ * @param table
+ * EFD table to reference
+ * @param socket_id
+ * Socket ID to use to lookup existing value (ideally caller's socket id)
+ * @param num_keys
+ * Number of keys in the key_list array, must be less than EFD_BURST_MAX
+ * @param key_list
+ * Array of num_keys pointers which point to keys to look up
+ * @param value_list
+ * Array of size num_keys where lookup values will be stored
+ */
+void
+rte_efd_lookup_bulk(const struct rte_efd_table *table, unsigned int socket_id,
+ int num_keys, const efd_key_t *const *key_list,
+ efd_value_t *value_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LIBEFD_H__ */
+
diff --git a/lib/librte_efd/rte_efd_version.map b/lib/librte_efd/rte_efd_version.map
new file mode 100644
index 0000000..91810b3
--- /dev/null
+++ b/lib/librte_efd/rte_efd_version.map
@@ -0,0 +1,12 @@
+DPDK_17.02 {
+ global:
+
+ rte_efd_create;
+ rte_efd_delete;
+ rte_efd_free;
+ rte_efd_lookup;
+ rte_efd_lookup_bulk;
+ rte_efd_update;
+
+ local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index f75f0e2..3956849 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -86,6 +86,7 @@ _LDLIBS-y += --whole-archive
_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER) += -lrte_timer
_LDLIBS-$(CONFIG_RTE_LIBRTE_HASH) += -lrte_hash
+_LDLIBS-$(CONFIG_RTE_LIBRTE_EFD) += -lrte_efd
_LDLIBS-$(CONFIG_RTE_LIBRTE_VHOST) += -lrte_vhost
_LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS) += -lrte_kvargs
--
2.7.4
^ permalink raw reply related
* [PATCH 2/2] examples/flow_distributor: sample app to demonstrate EFD usage
From: Pablo de Lara @ 2016-12-02 14:52 UTC (permalink / raw)
To: dev; +Cc: Pablo de Lara
In-Reply-To: <1480690340-17652-1-git-send-email-pablo.de.lara.guarch@intel.com>
This new sample app, based on the client/server sample app,
shows the user an scenario using the EFD library.
It consists of:
- A front-end server which has an EFD table that stores the
node id for each flow key, which will distribute the incoming
packets to the different nodes
- A back-end node, which has a hash table where node checks,
after reading packets coming from the server, whether the packet
is meant to be used in such node, in which case it will be TXed,
or not, in which case, packet will be dropped.
Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
examples/Makefile | 1 +
examples/flow_distributor/Makefile | 44 +++
examples/flow_distributor/distributor/Makefile | 57 ++++
examples/flow_distributor/distributor/args.c | 200 ++++++++++++
examples/flow_distributor/distributor/args.h | 39 +++
examples/flow_distributor/distributor/init.c | 371 ++++++++++++++++++++++
examples/flow_distributor/distributor/init.h | 76 +++++
examples/flow_distributor/distributor/main.c | 362 +++++++++++++++++++++
examples/flow_distributor/node/Makefile | 48 +++
examples/flow_distributor/node/node.c | 417 +++++++++++++++++++++++++
examples/flow_distributor/shared/common.h | 99 ++++++
11 files changed, 1714 insertions(+)
create mode 100644 examples/flow_distributor/Makefile
create mode 100644 examples/flow_distributor/distributor/Makefile
create mode 100644 examples/flow_distributor/distributor/args.c
create mode 100644 examples/flow_distributor/distributor/args.h
create mode 100644 examples/flow_distributor/distributor/init.c
create mode 100644 examples/flow_distributor/distributor/init.h
create mode 100644 examples/flow_distributor/distributor/main.c
create mode 100644 examples/flow_distributor/node/Makefile
create mode 100644 examples/flow_distributor/node/node.c
create mode 100644 examples/flow_distributor/shared/common.h
diff --git a/examples/Makefile b/examples/Makefile
index d49c7f2..b404982 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -45,6 +45,7 @@ DIRS-y += dpdk_qat
endif
DIRS-y += ethtool
DIRS-y += exception_path
+DIRS-$(CONFIG_RTE_LIBRTE_EFD) += flow_distributor
DIRS-y += helloworld
DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += ip_pipeline
ifeq ($(CONFIG_RTE_LIBRTE_LPM),y)
diff --git a/examples/flow_distributor/Makefile b/examples/flow_distributor/Makefile
new file mode 100644
index 0000000..d085e49
--- /dev/null
+++ b/examples/flow_distributor/Makefile
@@ -0,0 +1,44 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += distributor
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += node
+
+include $(RTE_SDK)/mk/rte.extsubdir.mk
diff --git a/examples/flow_distributor/distributor/Makefile b/examples/flow_distributor/distributor/Makefile
new file mode 100644
index 0000000..5a709ab
--- /dev/null
+++ b/examples/flow_distributor/distributor/Makefile
@@ -0,0 +1,57 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV), "linuxapp")
+$(error This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+endif
+
+# binary name
+APP = distributor
+
+# all source are stored in SRCS-y
+SRCS-y := main.c init.c args.c
+
+INC := $(wildcard *.h)
+
+CFLAGS += $(WERROR_FLAGS) -O3
+CFLAGS += -I$(SRCDIR)/../shared
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/flow_distributor/distributor/args.c b/examples/flow_distributor/distributor/args.c
new file mode 100644
index 0000000..3bd1ad6
--- /dev/null
+++ b/examples/flow_distributor/distributor/args.c
@@ -0,0 +1,200 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include <rte_memory.h>
+#include <rte_string_fns.h>
+
+#include "common.h"
+#include "args.h"
+#include "init.h"
+
+/* 1M flows by default */
+#define DEFAULT_NUM_FLOWS 0x100000
+
+/* global var for number of nodes - extern in header */
+uint8_t num_nodes;
+/* global var for number of flows - extern in header */
+uint32_t num_flows = DEFAULT_NUM_FLOWS;
+
+static const char *progname;
+
+/**
+ * Prints out usage information to stdout
+ */
+static void
+usage(void)
+{
+ printf("%s [EAL options] -- -p PORTMASK -n NUM_NODES -f NUM_FLOWS\n"
+ " -p PORTMASK: hexadecimal bitmask of ports to use\n"
+ " -n NUM_NODES: number of node processes to use\n"
+ " -f NUM_FLOWS: number of flows to be added in the EFD table\n",
+ progname);
+}
+
+/**
+ * The ports to be used by the application are passed in
+ * the form of a bitmask. This function parses the bitmask
+ * and places the port numbers to be used into the port[]
+ * array variable
+ */
+static int
+parse_portmask(uint8_t max_ports, const char *portmask)
+{
+ char *end = NULL;
+ unsigned long pm;
+ uint8_t count = 0;
+
+ if (portmask == NULL || *portmask == '\0')
+ return -1;
+
+ /* convert parameter to a number and verify */
+ pm = strtoul(portmask, &end, 16);
+ if (end == NULL || *end != '\0' || pm == 0)
+ return -1;
+
+ /* loop through bits of the mask and mark ports */
+ while (pm != 0) {
+ if (pm & 0x01) { /* bit is set in mask, use port */
+ if (count >= max_ports)
+ printf("WARNING: requested port %u not present"
+ " - ignoring\n", (unsigned int)count);
+ else
+ info->id[info->num_ports++] = count;
+ }
+ pm = (pm >> 1);
+ count++;
+ }
+
+ return 0;
+}
+
+/**
+ * Take the number of nodes parameter passed to the app
+ * and convert to a number to store in the num_nodes variable
+ */
+static int
+parse_num_nodes(const char *nodes)
+{
+ char *end = NULL;
+ unsigned long temp;
+
+ if (nodes == NULL || *nodes == '\0')
+ return -1;
+
+ temp = strtoul(nodes, &end, 10);
+ if (end == NULL || *end != '\0' || temp == 0)
+ return -1;
+
+ num_nodes = (uint8_t)temp;
+ return 0;
+}
+
+static int
+parse_num_flows(const char *flows)
+{
+ char *end = NULL;
+
+ /* parse hexadecimal string */
+ num_flows = strtoul(flows, &end, 16);
+ if ((flows[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+
+ if (num_flows == 0)
+ return -1;
+
+ return 0;
+}
+
+/**
+ * The application specific arguments follow the DPDK-specific
+ * arguments which are stripped by the DPDK init. This function
+ * processes these application arguments, printing usage info
+ * on error.
+ */
+int
+parse_app_args(uint8_t max_ports, int argc, char *argv[])
+{
+ int option_index, opt;
+ char **argvopt = argv;
+ static struct option lgopts[] = { /* no long options */
+ {NULL, 0, 0, 0 }
+ };
+ progname = argv[0];
+
+ while ((opt = getopt_long(argc, argvopt, "n:f:p:", lgopts,
+ &option_index)) != EOF) {
+ switch (opt) {
+ case 'p':
+ if (parse_portmask(max_ports, optarg) != 0) {
+ usage();
+ return -1;
+ }
+ break;
+ case 'n':
+ if (parse_num_nodes(optarg) != 0) {
+ usage();
+ return -1;
+ }
+ break;
+ case 'f':
+ if (parse_num_flows(optarg) != 0) {
+ usage();
+ return -1;
+ }
+ break;
+ default:
+ printf("ERROR: Unknown option '%c'\n", opt);
+ usage();
+ return -1;
+ }
+ }
+
+ if (info->num_ports == 0 || num_nodes == 0) {
+ usage();
+ return -1;
+ }
+
+ if (info->num_ports % 2 != 0) {
+ printf("ERROR: application requires an even "
+ "number of ports to use\n");
+ return -1;
+ }
+ return 0;
+}
diff --git a/examples/flow_distributor/distributor/args.h b/examples/flow_distributor/distributor/args.h
new file mode 100644
index 0000000..8b36148
--- /dev/null
+++ b/examples/flow_distributor/distributor/args.h
@@ -0,0 +1,39 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARGS_H_
+#define _ARGS_H_
+
+int parse_app_args(uint8_t max_ports, int argc, char *argv[]);
+
+#endif /* ifndef _ARGS_H_ */
diff --git a/examples/flow_distributor/distributor/init.c b/examples/flow_distributor/distributor/init.c
new file mode 100644
index 0000000..dff466c
--- /dev/null
+++ b/examples/flow_distributor/distributor/init.c
@@ -0,0 +1,371 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_byteorder.h>
+#include <rte_atomic.h>
+#include <rte_launch.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_debug.h>
+#include <rte_ring.h>
+#include <rte_log.h>
+#include <rte_mempool.h>
+#include <rte_memcpy.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_string_fns.h>
+#include <rte_cycles.h>
+#include <rte_efd.h>
+#include <rte_hash.h>
+
+#include "common.h"
+#include "args.h"
+#include "init.h"
+
+#define MBUFS_PER_NODE 1536
+#define MBUFS_PER_PORT 1536
+#define MBUF_CACHE_SIZE 512
+
+#define RTE_MP_RX_DESC_DEFAULT 512
+#define RTE_MP_TX_DESC_DEFAULT 512
+#define NODE_QUEUE_RINGSIZE 128
+
+#define NO_FLAGS 0
+
+/* The mbuf pool for packet rx */
+struct rte_mempool *pktmbuf_pool;
+
+/* array of info/queues for nodes */
+struct node *nodes;
+
+/* Flow distributor table */
+struct rte_efd_table *efd_table;
+
+/* Shared info between distributor and nodes */
+struct shared_info *info;
+
+/**
+ * Initialise the mbuf pool for packet reception for the NIC, and any other
+ * buffer pools needed by the app - currently none.
+ */
+static int
+init_mbuf_pools(void)
+{
+ const unsigned int num_mbufs = (num_nodes * MBUFS_PER_NODE) +
+ (info->num_ports * MBUFS_PER_PORT);
+
+ /*
+ * Don't pass single-producer/single-consumer flags to mbuf create as it
+ * seems faster to use a cache instead
+ */
+ printf("Creating mbuf pool '%s' [%u mbufs] ...\n",
+ PKTMBUF_POOL_NAME, num_mbufs);
+ pktmbuf_pool = rte_pktmbuf_pool_create(PKTMBUF_POOL_NAME, num_mbufs,
+ MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+
+ return pktmbuf_pool == NULL; /* 0 on success */
+}
+
+/**
+ * Initialise an individual port:
+ * - configure number of rx and tx rings
+ * - set up each rx ring, to pull from the main mbuf pool
+ * - set up each tx ring
+ * - start the port and report its status to stdout
+ */
+static int
+init_port(uint8_t port_num)
+{
+ /* for port configuration all features are off by default */
+ const struct rte_eth_conf port_conf = {
+ .rxmode = {
+ .mq_mode = ETH_MQ_RX_RSS
+ }
+ };
+ const uint16_t rx_rings = 1, tx_rings = num_nodes;
+ const uint16_t rx_ring_size = RTE_MP_RX_DESC_DEFAULT;
+ const uint16_t tx_ring_size = RTE_MP_TX_DESC_DEFAULT;
+
+ uint16_t q;
+ int retval;
+
+ printf("Port %u init ... ", (unsigned int)port_num);
+ fflush(stdout);
+
+ /*
+ * Standard DPDK port initialisation - config port, then set up
+ * rx and tx rings.
+ */
+ retval = rte_eth_dev_configure(port_num, rx_rings, tx_rings, &port_conf);
+ if (retval != 0)
+ return retval;
+
+ for (q = 0; q < rx_rings; q++) {
+ retval = rte_eth_rx_queue_setup(port_num, q, rx_ring_size,
+ rte_eth_dev_socket_id(port_num),
+ NULL, pktmbuf_pool);
+ if (retval < 0)
+ return retval;
+ }
+
+ for (q = 0; q < tx_rings; q++) {
+ retval = rte_eth_tx_queue_setup(port_num, q, tx_ring_size,
+ rte_eth_dev_socket_id(port_num),
+ NULL);
+ if (retval < 0)
+ return retval;
+ }
+
+ rte_eth_promiscuous_enable(port_num);
+
+ retval = rte_eth_dev_start(port_num);
+ if (retval < 0)
+ return retval;
+
+ printf("done:\n");
+
+ return 0;
+}
+
+/**
+ * Set up the DPDK rings which will be used to pass packets, via
+ * pointers, between the multi-process distributor and node processes.
+ * Each node needs one RX queue.
+ */
+static int
+init_shm_rings(void)
+{
+ unsigned int i;
+ unsigned int socket_id;
+ const char *q_name;
+ const unsigned int ringsize = NODE_QUEUE_RINGSIZE;
+
+ nodes = rte_malloc("node details",
+ sizeof(*nodes) * num_nodes, 0);
+ if (nodes == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot allocate memory for "
+ "node program details\n");
+
+ for (i = 0; i < num_nodes; i++) {
+ /* Create an RX queue for each node */
+ socket_id = rte_socket_id();
+ q_name = get_rx_queue_name(i);
+ nodes[i].rx_q = rte_ring_create(q_name,
+ ringsize, socket_id,
+ RING_F_SP_ENQ | RING_F_SC_DEQ);
+ if (nodes[i].rx_q == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot create rx ring queue "
+ "for node %u\n", i);
+ }
+ return 0;
+}
+
+/*
+ * Create flow distributor table which will contain all the flows
+ * that will be distributed among the nodes
+ */
+static void
+create_flow_distributor_table(void)
+{
+ uint8_t socket_id = rte_socket_id();
+
+ /* create table */
+ efd_table = rte_efd_create("flow table", num_flows * 2, 1 << socket_id,
+ socket_id);
+
+ if (efd_table == NULL)
+ rte_exit(EXIT_FAILURE, "Problem creating the flow table\n");
+}
+
+static void
+populate_flow_distributor_table(void)
+{
+ unsigned int i;
+ int32_t ret;
+ uint32_t ip_dst;
+ uint8_t socket_id = rte_socket_id();
+ uint64_t node_id;
+
+ /* Add flows in tables */
+ for (i = 0; i < num_flows; i++) {
+ node_id = i % num_nodes;
+
+ ip_dst = rte_cpu_to_be_32(i);
+ ret = rte_efd_update(efd_table, socket_id,
+ (efd_key_t *)&ip_dst, (efd_value_t)node_id);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Unable to add entry %u in "
+ "flow distributor table\n", i);
+ }
+
+ printf("EFD table: Adding 0x%x keys\n", num_flows);
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+ uint8_t portid, count, all_ports_up, print_flag = 0;
+ struct rte_eth_link link;
+
+ printf("\nChecking link status");
+ fflush(stdout);
+ for (count = 0; count <= MAX_CHECK_TIME; count++) {
+ all_ports_up = 1;
+ for (portid = 0; portid < port_num; portid++) {
+ if ((port_mask & (1 << info->id[portid])) == 0)
+ continue;
+ memset(&link, 0, sizeof(link));
+ rte_eth_link_get_nowait(info->id[portid], &link);
+ /* print link status if flag set */
+ if (print_flag == 1) {
+ if (link.link_status)
+ printf("Port %d Link Up - speed %u "
+ "Mbps - %s\n", info->id[portid],
+ (unsigned int)link.link_speed,
+ (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+ ("full-duplex") : ("half-duplex\n"));
+ else
+ printf("Port %d Link Down\n",
+ (uint8_t)info->id[portid]);
+ continue;
+ }
+ /* clear all_ports_up flag if any link down */
+ if (link.link_status == ETH_LINK_DOWN) {
+ all_ports_up = 0;
+ break;
+ }
+ }
+ /* after finally printing all link status, get out */
+ if (print_flag == 1)
+ break;
+
+ if (all_ports_up == 0) {
+ printf(".");
+ fflush(stdout);
+ rte_delay_ms(CHECK_INTERVAL);
+ }
+
+ /* set the print_flag if all ports up or timeout */
+ if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+ print_flag = 1;
+ printf("done\n");
+ }
+ }
+}
+
+/**
+ * Main init function for the multi-process distributor app,
+ * calls subfunctions to do each stage of the initialisation.
+ */
+int
+init(int argc, char *argv[])
+{
+ int retval;
+ const struct rte_memzone *mz;
+ uint8_t i, total_ports;
+
+ /* init EAL, parsing EAL args */
+ retval = rte_eal_init(argc, argv);
+ if (retval < 0)
+ return -1;
+ argc -= retval;
+ argv += retval;
+
+ /* get total number of ports */
+ total_ports = rte_eth_dev_count();
+
+ /* set up array for port data */
+ mz = rte_memzone_reserve(MZ_SHARED_INFO, sizeof(*info),
+ rte_socket_id(), NO_FLAGS);
+ if (mz == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot reserve memory zone "
+ "for port information\n");
+ memset(mz->addr, 0, sizeof(*info));
+ info = mz->addr;
+
+ /* parse additional, application arguments */
+ retval = parse_app_args(total_ports, argc, argv);
+ if (retval != 0)
+ return -1;
+
+ /* initialise mbuf pools */
+ retval = init_mbuf_pools();
+ if (retval != 0)
+ rte_exit(EXIT_FAILURE, "Cannot create needed mbuf pools\n");
+
+ /* now initialise the ports we will use */
+ for (i = 0; i < info->num_ports; i++) {
+ retval = init_port(info->id[i]);
+ if (retval != 0)
+ rte_exit(EXIT_FAILURE, "Cannot initialise port %u\n",
+ (unsigned int) i);
+ }
+
+ check_all_ports_link_status(info->num_ports, (~0x0));
+
+ /* initialise the node queues/rings for inter-eu comms */
+ init_shm_rings();
+
+ /* Create the flow distributor table */
+ create_flow_distributor_table();
+
+ /* Populate the flow distributor table */
+ populate_flow_distributor_table();
+
+ /* Share the total number of nodes */
+ info->num_nodes = num_nodes;
+
+ /* Share the total number of flows */
+ info->num_flows = num_flows;
+ return 0;
+}
diff --git a/examples/flow_distributor/distributor/init.h b/examples/flow_distributor/distributor/init.h
new file mode 100644
index 0000000..ea0c0d4
--- /dev/null
+++ b/examples/flow_distributor/distributor/init.h
@@ -0,0 +1,76 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _INIT_H_
+#define _INIT_H_
+
+/*
+ * #include <rte_ring.h>
+ * #include "args.h"
+ */
+
+/*
+ * Define a node structure with all needed info, including
+ * stats from the nodes.
+ */
+struct node {
+ struct rte_ring *rx_q;
+ unsigned int node_id;
+ /* these stats hold how many packets the node will actually receive,
+ * and how many packets were dropped because the node's queue was full.
+ * The port-info stats, in contrast, record how many packets were received
+ * or transmitted on an actual NIC port.
+ */
+ struct {
+ uint64_t rx;
+ uint64_t rx_drop;
+ } stats;
+};
+
+extern struct rte_efd_table *efd_table;
+extern struct node *nodes;
+
+/*
+ * shared information between distributor and nodes: number of clients,
+ * port numbers, rx and tx stats etc.
+ */
+extern struct shared_info *info;
+
+extern struct rte_mempool *pktmbuf_pool;
+extern uint8_t num_nodes;
+extern unsigned int num_sockets;
+extern uint32_t num_flows;
+
+int init(int argc, char *argv[]);
+
+#endif /* ifndef _INIT_H_ */
diff --git a/examples/flow_distributor/distributor/main.c b/examples/flow_distributor/distributor/main.c
new file mode 100644
index 0000000..efe6960
--- /dev/null
+++ b/examples/flow_distributor/distributor/main.c
@@ -0,0 +1,362 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <inttypes.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <netinet/ip.h>
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_byteorder.h>
+#include <rte_launch.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_atomic.h>
+#include <rte_ring.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_mempool.h>
+#include <rte_memcpy.h>
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ethdev.h>
+#include <rte_byteorder.h>
+#include <rte_malloc.h>
+#include <rte_string_fns.h>
+#include <rte_efd.h>
+#include <rte_ip.h>
+
+#include "common.h"
+#include "args.h"
+#include "init.h"
+
+/*
+ * When doing reads from the NIC or the node queues,
+ * use this batch size
+ */
+#define PACKET_READ_SIZE 32
+
+/*
+ * Local buffers to put packets in, used to send packets in bursts to the
+ * nodes
+ */
+struct node_rx_buf {
+ struct rte_mbuf *buffer[PACKET_READ_SIZE];
+ uint16_t count;
+};
+
+struct flow_distributor_stats {
+ uint64_t distributed;
+ uint64_t drop;
+} flow_dist_stats;
+
+/* One buffer per node rx queue - dynamically allocate array */
+static struct node_rx_buf *cl_rx_buf;
+
+static const char *
+get_printable_mac_addr(uint8_t port)
+{
+ static const char err_address[] = "00:00:00:00:00:00";
+ static char addresses[RTE_MAX_ETHPORTS][sizeof(err_address)];
+ struct ether_addr mac;
+
+ if (unlikely(port >= RTE_MAX_ETHPORTS))
+ return err_address;
+ if (unlikely(addresses[port][0] == '\0')) {
+ rte_eth_macaddr_get(port, &mac);
+ snprintf(addresses[port], sizeof(addresses[port]),
+ "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac.addr_bytes[0], mac.addr_bytes[1],
+ mac.addr_bytes[2], mac.addr_bytes[3],
+ mac.addr_bytes[4], mac.addr_bytes[5]);
+ }
+ return addresses[port];
+}
+
+/*
+ * This function displays the recorded statistics for each port
+ * and for each node. It uses ANSI terminal codes to clear
+ * screen when called. It is called from a single non-master
+ * thread in the distributor process, when the process is run with more
+ * than one lcore enabled.
+ */
+static void
+do_stats_display(void)
+{
+ unsigned int i, j;
+ const char clr[] = {27, '[', '2', 'J', '\0'};
+ const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'};
+ uint64_t port_tx[RTE_MAX_ETHPORTS], port_tx_drop[RTE_MAX_ETHPORTS];
+ uint64_t node_tx[MAX_NODES], node_tx_drop[MAX_NODES];
+
+ /* to get TX stats, we need to do some summing calculations */
+ memset(port_tx, 0, sizeof(port_tx));
+ memset(port_tx_drop, 0, sizeof(port_tx_drop));
+ memset(node_tx, 0, sizeof(node_tx));
+ memset(node_tx_drop, 0, sizeof(node_tx_drop));
+
+ for (i = 0; i < num_nodes; i++) {
+ const struct tx_stats *tx = &info->tx_stats[i];
+
+ for (j = 0; j < info->num_ports; j++) {
+ const uint64_t tx_val = tx->tx[info->id[j]];
+ const uint64_t drop_val = tx->tx_drop[info->id[j]];
+
+ port_tx[j] += tx_val;
+ port_tx_drop[j] += drop_val;
+ node_tx[i] += tx_val;
+ node_tx_drop[i] += drop_val;
+ }
+ }
+
+ /* Clear screen and move to top left */
+ printf("%s%s", clr, topLeft);
+
+ printf("PORTS\n");
+ printf("-----\n");
+ for (i = 0; i < info->num_ports; i++)
+ printf("Port %u: '%s'\t", (unsigned int)info->id[i],
+ get_printable_mac_addr(info->id[i]));
+ printf("\n\n");
+ for (i = 0; i < info->num_ports; i++) {
+ printf("Port %u - rx: %9"PRIu64"\t"
+ "tx: %9"PRIu64"\n",
+ (unsigned int)info->id[i], info->rx_stats.rx[i],
+ port_tx[i]);
+ }
+
+ printf("\nFLOW DISTRIBUTOR\n");
+ printf("-----\n");
+ printf("distributed: %9"PRIu64", drop: %9"PRIu64"\n",
+ flow_dist_stats.distributed, flow_dist_stats.drop);
+
+ printf("\nNODES\n");
+ printf("-------\n");
+ for (i = 0; i < num_nodes; i++) {
+ const unsigned long long rx = nodes[i].stats.rx;
+ const unsigned long long rx_drop = nodes[i].stats.rx_drop;
+ const struct filter_stats *filter = &info->filter_stats[i];
+
+ printf("Node %2u - rx: %9llu, rx_drop: %9llu\n"
+ " tx: %9"PRIu64", tx_drop: %9"PRIu64"\n"
+ " filter_passed: %9"PRIu64", "
+ "filter_drop: %9"PRIu64"\n",
+ i, rx, rx_drop, node_tx[i], node_tx_drop[i],
+ filter->passed, filter->drop);
+ }
+
+ printf("\n");
+}
+
+/*
+ * The function called from each non-master lcore used by the process.
+ * The test_and_set function is used to randomly pick a single lcore on which
+ * the code to display the statistics will run. Otherwise, the code just
+ * repeatedly sleeps.
+ */
+static int
+sleep_lcore(__attribute__((unused)) void *dummy)
+{
+ /* Used to pick a display thread - static, so zero-initialised */
+ static rte_atomic32_t display_stats;
+
+ /* Only one core should display stats */
+ if (rte_atomic32_test_and_set(&display_stats)) {
+ const unsigned int sleeptime = 1;
+
+ printf("Core %u displaying statistics\n", rte_lcore_id());
+
+ /* Longer initial pause so above printf is seen */
+ sleep(sleeptime * 3);
+
+ /* Loop forever: sleep always returns 0 or <= param */
+ while (sleep(sleeptime) <= sleeptime)
+ do_stats_display();
+ }
+ return 0;
+}
+
+/*
+ * Function to set all the node statistic values to zero.
+ * Called at program startup.
+ */
+static void
+clear_stats(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_nodes; i++)
+ nodes[i].stats.rx = nodes[i].stats.rx_drop = 0;
+}
+
+/*
+ * send a burst of traffic to a node, assuming there are packets
+ * available to be sent to this node
+ */
+static void
+flush_rx_queue(uint16_t node)
+{
+ uint16_t j;
+ struct node *cl;
+
+ if (cl_rx_buf[node].count == 0)
+ return;
+
+ cl = &nodes[node];
+ if (rte_ring_enqueue_bulk(cl->rx_q, (void **)cl_rx_buf[node].buffer,
+ cl_rx_buf[node].count) != 0){
+ for (j = 0; j < cl_rx_buf[node].count; j++)
+ rte_pktmbuf_free(cl_rx_buf[node].buffer[j]);
+ cl->stats.rx_drop += cl_rx_buf[node].count;
+ } else
+ cl->stats.rx += cl_rx_buf[node].count;
+
+ cl_rx_buf[node].count = 0;
+}
+
+/*
+ * marks a packet down to be sent to a particular node process
+ */
+static inline void
+enqueue_rx_packet(uint8_t node, struct rte_mbuf *buf)
+{
+ cl_rx_buf[node].buffer[cl_rx_buf[node].count++] = buf;
+}
+
+/*
+ * This function takes a group of packets and routes them
+ * individually to the node process. Very simply round-robins the packets
+ * without checking any of the packet contents.
+ */
+static void
+process_packets(uint32_t port_num __rte_unused, struct rte_mbuf *pkts[],
+ uint16_t rx_count, unsigned int socket_id)
+{
+ uint16_t i;
+ uint8_t node;
+ efd_value_t data[EFD_BURST_MAX];
+ const efd_key_t *key_ptrs[EFD_BURST_MAX];
+
+ struct ipv4_hdr *ipv4_hdr;
+ uint32_t ipv4_dst_ip[EFD_BURST_MAX];
+
+ for (i = 0; i < rx_count; i++) {
+ /* Handle IPv4 header.*/
+ ipv4_hdr = rte_pktmbuf_mtod_offset(pkts[i], struct ipv4_hdr *,
+ sizeof(struct ether_hdr));
+ ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
+ key_ptrs[i] = (efd_key_t *)&ipv4_dst_ip[i];
+ }
+
+ rte_efd_lookup_bulk(efd_table, socket_id, rx_count,
+ (const efd_key_t **) key_ptrs, data);
+ for (i = 0; i < rx_count; i++) {
+ node = (uint8_t) ((uintptr_t)data[i]);
+
+ if (node >= num_nodes) {
+ /*
+ * Node is out of range, which means that
+ * flow has not been inserted
+ */
+ flow_dist_stats.drop++;
+ rte_pktmbuf_free(pkts[i]);
+ } else {
+ flow_dist_stats.distributed++;
+ enqueue_rx_packet(node, pkts[i]);
+ }
+ }
+
+ for (i = 0; i < num_nodes; i++)
+ flush_rx_queue(i);
+}
+
+/*
+ * Function called by the master lcore of the DPDK process.
+ */
+static void
+do_packet_forwarding(void)
+{
+ unsigned int port_num = 0; /* indexes the port[] array */
+ unsigned int socket_id = rte_socket_id();
+
+ for (;;) {
+ struct rte_mbuf *buf[PACKET_READ_SIZE];
+ uint16_t rx_count;
+
+ /* read a port */
+ rx_count = rte_eth_rx_burst(info->id[port_num], 0,
+ buf, PACKET_READ_SIZE);
+ info->rx_stats.rx[port_num] += rx_count;
+
+ /* Now process the NIC packets read */
+ if (likely(rx_count > 0))
+ process_packets(port_num, buf, rx_count, socket_id);
+
+ /* move to next port */
+ if (++port_num == info->num_ports)
+ port_num = 0;
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ /* initialise the system */
+ if (init(argc, argv) < 0)
+ return -1;
+ RTE_LOG(INFO, APP, "Finished Process Init.\n");
+
+ cl_rx_buf = calloc(num_nodes, sizeof(cl_rx_buf[0]));
+
+ /* clear statistics */
+ clear_stats();
+
+ /* put all other cores to sleep bar master */
+ rte_eal_mp_remote_launch(sleep_lcore, NULL, SKIP_MASTER);
+
+ do_packet_forwarding();
+ return 0;
+}
diff --git a/examples/flow_distributor/node/Makefile b/examples/flow_distributor/node/Makefile
new file mode 100644
index 0000000..59aac28
--- /dev/null
+++ b/examples/flow_distributor/node/Makefile
@@ -0,0 +1,48 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = node
+
+# all source are stored in SRCS-y
+SRCS-y := node.c
+
+CFLAGS += $(WERROR_FLAGS) -O3
+CFLAGS += -I$(SRCDIR)/../shared
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/flow_distributor/node/node.c b/examples/flow_distributor/node/node.c
new file mode 100644
index 0000000..e68f252
--- /dev/null
+++ b/examples/flow_distributor/node/node.c
@@ -0,0 +1,417 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_log.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_lcore.h>
+#include <rte_ring.h>
+#include <rte_launch.h>
+#include <rte_lcore.h>
+#include <rte_debug.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_string_fns.h>
+#include <rte_ip.h>
+
+#include "common.h"
+
+/* Number of packets to attempt to read from queue */
+#define PKT_READ_SIZE ((uint16_t)32)
+
+/*
+ * Our node id number - tells us which rx queue to read, and NIC TX
+ * queue to write to.
+ */
+static uint8_t node_id;
+
+#define MBQ_CAPACITY 32
+
+/* maps input ports to output ports for packets */
+static uint8_t output_ports[RTE_MAX_ETHPORTS];
+
+/* buffers up a set of packet that are ready to send */
+struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
+
+/* shared data from distributor. We update statistics here */
+static struct tx_stats *tx_stats;
+
+static struct filter_stats *filter_stats;
+
+/*
+ * print a usage message
+ */
+static void
+usage(const char *progname)
+{
+ printf("Usage: %s [EAL args] -- -n <node_id>\n\n", progname);
+}
+
+/*
+ * Convert the node id number from a string to an int.
+ */
+static int
+parse_node_num(const char *node)
+{
+ char *end = NULL;
+ unsigned long temp;
+
+ if (node == NULL || *node == '\0')
+ return -1;
+
+ temp = strtoul(node, &end, 10);
+ if (end == NULL || *end != '\0')
+ return -1;
+
+ node_id = (uint8_t)temp;
+ return 0;
+}
+
+/*
+ * Parse the application arguments to the node app.
+ */
+static int
+parse_app_args(int argc, char *argv[])
+{
+ int option_index, opt;
+ char **argvopt = argv;
+ const char *progname = NULL;
+ static struct option lgopts[] = { /* no long options */
+ {NULL, 0, 0, 0 }
+ };
+ progname = argv[0];
+
+ while ((opt = getopt_long(argc, argvopt, "n:", lgopts,
+ &option_index)) != EOF) {
+ switch (opt) {
+ case 'n':
+ if (parse_node_num(optarg) != 0) {
+ usage(progname);
+ return -1;
+ }
+ break;
+ default:
+ usage(progname);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Tx buffer error callback
+ */
+static void
+flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count,
+ void *userdata) {
+ int i;
+ uint8_t port_id = (uintptr_t)userdata;
+
+ tx_stats->tx_drop[port_id] += count;
+
+ /* free the mbufs which failed from transmit */
+ for (i = 0; i < count; i++)
+ rte_pktmbuf_free(unsent[i]);
+
+}
+
+static void
+configure_tx_buffer(uint8_t port_id, uint16_t size)
+{
+ int ret;
+
+ /* Initialize TX buffers */
+ tx_buffer[port_id] = rte_zmalloc_socket("tx_buffer",
+ RTE_ETH_TX_BUFFER_SIZE(size), 0,
+ rte_eth_dev_socket_id(port_id));
+ if (tx_buffer[port_id] == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx "
+ "on port %u\n", (unsigned int) port_id);
+
+ rte_eth_tx_buffer_init(tx_buffer[port_id], size);
+
+ ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[port_id],
+ flush_tx_error_callback, (void *)(intptr_t)port_id);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Cannot set error callback for "
+ "tx buffer on port %u\n", (unsigned int) port_id);
+}
+
+/*
+ * set up output ports so that all traffic on port gets sent out
+ * its paired port. Index using actual port numbers since that is
+ * what comes in the mbuf structure.
+ */
+static void
+configure_output_ports(const struct shared_info *info)
+{
+ int i;
+
+ if (info->num_ports > RTE_MAX_ETHPORTS)
+ rte_exit(EXIT_FAILURE, "Too many ethernet ports. "
+ "RTE_MAX_ETHPORTS = %u\n",
+ (unsigned int)RTE_MAX_ETHPORTS);
+ for (i = 0; i < info->num_ports - 1; i += 2) {
+ uint8_t p1 = info->id[i];
+ uint8_t p2 = info->id[i+1];
+
+ output_ports[p1] = p2;
+ output_ports[p2] = p1;
+
+ configure_tx_buffer(p1, MBQ_CAPACITY);
+ configure_tx_buffer(p2, MBQ_CAPACITY);
+
+ }
+}
+
+/*
+ * Create the hash table that will contain the flows that
+ * the node will handle, which will be used to decide if packet
+ * is transmitted or dropped.
+ */
+static struct rte_hash *
+create_hash_table(const struct shared_info *info)
+{
+ uint32_t num_flows_node = info->num_flows / info->num_nodes;
+ char name[RTE_HASH_NAMESIZE];
+ struct rte_hash *h;
+
+ /* create table */
+ struct rte_hash_parameters hash_params = {
+ .entries = num_flows_node * 2, /* table load = 50% */
+ .key_len = sizeof(uint32_t), /* Store IPv4 dest IP address */
+ .socket_id = rte_socket_id(),
+ .hash_func_init_val = 0,
+ };
+
+ snprintf(name, sizeof(name), "hash_table_%d", node_id);
+ hash_params.name = name;
+ h = rte_hash_create(&hash_params);
+
+ if (h == NULL)
+ rte_exit(EXIT_FAILURE,
+ "Problem creating the hash table for node %d\n",
+ node_id);
+ return h;
+}
+
+static void
+populate_hash_table(const struct rte_hash *h, const struct shared_info *info)
+{
+ unsigned int i;
+ int32_t ret;
+ uint32_t ip_dst;
+ uint32_t num_flows_node = 0;
+ uint64_t target_node;
+
+ /* Add flows in table */
+ for (i = 0; i < info->num_flows; i++) {
+ target_node = i % info->num_nodes;
+ if (target_node != node_id)
+ continue;
+
+ ip_dst = rte_cpu_to_be_32(i);
+
+ ret = rte_hash_add_key(h, (void *) &ip_dst);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Unable to add entry %u "
+ "in hash table\n", i);
+ else
+ num_flows_node++;
+
+ }
+
+ printf("Hash table: Adding 0x%x keys\n", num_flows_node);
+}
+
+/*
+ * This function performs routing of packets
+ * Just sends each input packet out an output port based solely on the input
+ * port it arrived on.
+ */
+static inline void
+transmit_packet(struct rte_mbuf *buf)
+{
+ int sent;
+ const uint8_t in_port = buf->port;
+ const uint8_t out_port = output_ports[in_port];
+ struct rte_eth_dev_tx_buffer *buffer = tx_buffer[out_port];
+
+ sent = rte_eth_tx_buffer(out_port, node_id, buffer, buf);
+ if (sent)
+ tx_stats->tx[out_port] += sent;
+
+}
+
+static inline int
+handle_packets(struct rte_hash *h, struct rte_mbuf **bufs, uint16_t num_packets)
+{
+ struct ipv4_hdr *ipv4_hdr;
+ uint32_t ipv4_dst_ip[PKT_READ_SIZE];
+ const void *key_ptrs[PKT_READ_SIZE];
+ unsigned int i;
+ int32_t positions[PKT_READ_SIZE] = {0};
+
+ for (i = 0; i < num_packets; i++) {
+ /* Handle IPv4 header.*/
+ ipv4_hdr = rte_pktmbuf_mtod_offset(bufs[i], struct ipv4_hdr *,
+ sizeof(struct ether_hdr));
+ ipv4_dst_ip[i] = ipv4_hdr->dst_addr;
+ key_ptrs[i] = &ipv4_dst_ip[i];
+ }
+ /* Check if packets belongs to any flows handled by this node */
+ rte_hash_lookup_bulk(h, key_ptrs, num_packets, positions);
+
+ for (i = 0; i < num_packets; i++) {
+ if (likely(positions[i] >= 0)) {
+ filter_stats->passed++;
+ transmit_packet(bufs[i]);
+ } else {
+ filter_stats->drop++;
+ /* Drop packet, as flow is not handled by this node */
+ rte_pktmbuf_free(bufs[i]);
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Application main function - loops through
+ * receiving and processing packets. Never returns
+ */
+int
+main(int argc, char *argv[])
+{
+ const struct rte_memzone *mz;
+ struct rte_ring *rx_ring;
+ struct rte_hash *h;
+ struct rte_mempool *mp;
+ struct shared_info *info;
+ int need_flush = 0; /* indicates whether we have unsent packets */
+ int retval;
+ void *pkts[PKT_READ_SIZE];
+ uint16_t sent;
+
+ retval = rte_eal_init(argc, argv);
+ if (retval < 0)
+ return -1;
+ argc -= retval;
+ argv += retval;
+
+ if (parse_app_args(argc, argv) < 0)
+ rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n");
+
+ if (rte_eth_dev_count() == 0)
+ rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+ rx_ring = rte_ring_lookup(get_rx_queue_name(node_id));
+ if (rx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot get RX ring - "
+ "is distributor process running?\n");
+
+ mp = rte_mempool_lookup(PKTMBUF_POOL_NAME);
+ if (mp == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n");
+
+ mz = rte_memzone_lookup(MZ_SHARED_INFO);
+ if (mz == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot get port info structure\n");
+ info = mz->addr;
+ tx_stats = &(info->tx_stats[node_id]);
+ filter_stats = &(info->filter_stats[node_id]);
+
+ configure_output_ports(info);
+
+ h = create_hash_table(info);
+
+ populate_hash_table(h, info);
+
+ RTE_LOG(INFO, APP, "Finished Process Init.\n");
+
+ printf("\nNode process %d handling packets\n", node_id);
+ printf("[Press Ctrl-C to quit ...]\n");
+
+ for (;;) {
+ uint16_t rx_pkts = PKT_READ_SIZE;
+ uint8_t port;
+
+ /*
+ * Try dequeuing max possible packets first, if that fails,
+ * get the most we can. Loop body should only execute once,
+ * maximum
+ */
+ while (rx_pkts > 0 &&
+ unlikely(rte_ring_dequeue_bulk(rx_ring, pkts,
+ rx_pkts) != 0))
+ rx_pkts = (uint16_t)RTE_MIN(rte_ring_count(rx_ring),
+ PKT_READ_SIZE);
+
+ if (unlikely(rx_pkts == 0)) {
+ if (need_flush)
+ for (port = 0; port < info->num_ports; port++) {
+ sent = rte_eth_tx_buffer_flush(info->id[port],
+ node_id, tx_buffer[port]);
+ if (unlikely(sent))
+ tx_stats->tx[port] += sent;
+ }
+ need_flush = 0;
+ continue;
+ }
+
+ handle_packets(h, (struct rte_mbuf **)pkts, rx_pkts);
+
+ need_flush = 1;
+ }
+}
diff --git a/examples/flow_distributor/shared/common.h b/examples/flow_distributor/shared/common.h
new file mode 100644
index 0000000..66c5574
--- /dev/null
+++ b/examples/flow_distributor/shared/common.h
@@ -0,0 +1,99 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <rte_hash_crc.h>
+#include <rte_hash.h>
+
+#define MAX_NODES 16
+/*
+ * Shared port info, including statistics information for display by distributor.
+ * Structure will be put in a memzone.
+ * - All port id values share one cache line as this data will be read-only
+ * during operation.
+ * - All rx statistic values share cache lines, as this data is written only
+ * by the distributor process. (rare reads by stats display)
+ * - The tx statistics have values for all ports per cache line, but the stats
+ * themselves are written by the nodes, so we have a distinct set, on different
+ * cache lines for each node to use.
+ */
+struct rx_stats {
+ uint64_t rx[RTE_MAX_ETHPORTS];
+} __rte_cache_aligned;
+
+struct tx_stats {
+ uint64_t tx[RTE_MAX_ETHPORTS];
+ uint64_t tx_drop[RTE_MAX_ETHPORTS];
+} __rte_cache_aligned;
+
+struct filter_stats {
+ uint64_t drop;
+ uint64_t passed;
+} __rte_cache_aligned;
+
+struct shared_info {
+ uint8_t num_nodes;
+ uint8_t num_ports;
+ uint32_t num_flows;
+ uint8_t id[RTE_MAX_ETHPORTS];
+ struct rx_stats rx_stats;
+ struct tx_stats tx_stats[MAX_NODES];
+ struct filter_stats filter_stats[MAX_NODES];
+};
+
+/* define common names for structures shared between distributor and node */
+#define MP_NODE_RXQ_NAME "MProc_Node_%u_RX"
+#define PKTMBUF_POOL_NAME "MProc_pktmbuf_pool"
+#define MZ_SHARED_INFO "MProc_shared_info"
+
+/*
+ * Given the rx queue name template above, get the queue name
+ */
+static inline const char *
+get_rx_queue_name(unsigned int id)
+{
+ /*
+ * Buffer for return value. Size calculated by %u being replaced
+ * by maximum 3 digits (plus an extra byte for safety)
+ */
+ static char buffer[sizeof(MP_NODE_RXQ_NAME) + 2];
+
+ snprintf(buffer, sizeof(buffer) - 1, MP_NODE_RXQ_NAME, id);
+ return buffer;
+}
+
+#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1
+
+#endif
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v2 01/55] net/sfc: libefx-based PMD stub sufficient to build and init
From: Ferruh Yigit @ 2016-12-02 14:54 UTC (permalink / raw)
To: Andrew Rybchenko, dev
In-Reply-To: <1480436367-20749-2-git-send-email-arybchenko@solarflare.com>
On 11/29/2016 4:18 PM, Andrew Rybchenko wrote:
> The PMD is put into the sfc/efx subdirectory to have a place for
.. into sfc subdirectory ..
> the second PMD and library shared by both.
Since all will go into same (sfc) folder, should mention from this? This
looks like justification of previous sfc/efx.
>
> Enable the PMD by default on supported configuratons.
>
> Reviewed-by: Andy Moreton <amoreton@solarflare.com>
> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
> ---
^ permalink raw reply
* Re: [PATCH v2 00/55] Solarflare libefx-based PMD
From: Ferruh Yigit @ 2016-12-02 14:55 UTC (permalink / raw)
To: Andrew Rybchenko, dev
In-Reply-To: <1480436367-20749-1-git-send-email-arybchenko@solarflare.com>
On 11/29/2016 4:18 PM, Andrew Rybchenko wrote:
> The patch series adds Solarflare libefx-based network PMD.
>
> This version of the driver supports Solarflare SFN7xxx and SFN8xxx
> families of 10/40 Gbps adapters.
>
> libefx is a platform-independent library to implement drivers for
> Solarflare network adapters. It provides unified adapter family
> independent interface (if possible). FreeBSD [1] and illumos [2]
> drivers are built on top of the library.
>
> The patch series could be logically structured into 5 sub-series:
> 1. (1) add the driver skeleton including documentation
> 2. (2-30) import libefx and include it in build with the latest patch
> 3. (31-42) implement minimal device level operations in steps
> 4. (43-50) implement Rx subsystem
> 5. (51-55) implement Tx subsystem
>
> Functional driver with multi-queue support capable to send and receive
> traffic appears with the last patch in the series.
>
> The following design decisions are made during development:
>
> 1. Since libefx uses positive errno return codes, positive errno
> return codes are used inside the driver and coversion to negative
> is done on return from eth_dev_ops callbacks. We think that it
> is the less error-prone way.
>
> 2. Own event queue (a way to deliver events from HW to host CPU) is
> used for house-keeping (e.g. link status notifications), each Tx
> and each Rx queue. No locks on datapath are requires in this case.
>
> 3. Alarm is used to periodically poll house-keeping event queue.
> The event queue is used to deliver link status change notifications,
> Rx/Tx queue flush events, SRAM events. It is not used on datapath.
> The event queue polling is protected using spin-lock since
> concurrent access from different contexts is possible (e.g. device
> stop when polling alarm is running).
>
> [1] https://svnweb.freebsd.org/base/head/sys/dev/sfxge/common/
> [2] https://github.com/illumos/illumos-gate/tree/master/usr/src/uts/common/io/sfxge/common/
>
> ---
>
> v2:
> * Fix spelling
> * Fix ICC and clang build warnings
> * Remove efx subdirectory
> * Fix bug in Makefile which results in duplication of warnings options
> * Use WERROR_FLAGS and remove warnings disabling for the PMD itself
> * Comment enabled EFSYS_OPT_
> * Use space after #define instead of TAB
> * Update version map to upcoming release
> * Use bool for boolean_t in efsys.h
>
>
> Andrew Rybchenko (48):
> net/sfc: libefx-based PMD stub sufficient to build and init
> net/sfc: import libefx base
> net/sfc: import libefx register definitions
> net/sfc: import libefx filters support
> net/sfc: import libefx MCDI definition
> net/sfc: import libefx MCDI implementation
> net/sfc: import libefx MCDI logging support
> net/sfc: import libefx MCDI proxy authorization support
> net/sfc: import libefx 5xxx/6xxx family support
> net/sfc: import libefx SFN7xxx family support
> net/sfc: import libefx SFN8xxx family support
> net/sfc: import libefx diagnostics support
> net/sfc: import libefx built-in selftest support
> net/sfc: import libefx software per-queue statistics support
> net/sfc: import libefx PHY flags control support
> net/sfc: import libefx PHY statistics support
> net/sfc: import libefx PHY LEDs control support
> net/sfc: import libefx MAC statistics support
> net/sfc: import libefx event prefetch support
> net/sfc: import libefx Rx scatter support
> net/sfc: import libefx RSS support
> net/sfc: import libefx loopback control support
> net/sfc: import libefx monitors statistics support
> net/sfc: import libefx support to access monitors via MCDI
> net/sfc: import libefx support for Rx packed stream mode
> net/sfc: import libefx NVRAM support
> net/sfc: import libefx VPD support
> net/sfc: import libefx bootrom configuration support
> net/sfc: import libefx licensing support
> net/sfc: implement driver operation to init device on attach
> net/sfc: add device configure and close stubs
> net/sfc: add device configuration checks
> net/sfc: implement device start and stop operations
> net/sfc: make available resources estimation and allocation
> net/sfc: interrupts support sufficient for event queue init
> net/sfc: implement event queue support
> net/sfc: implement EVQ dummy exception handling
> net/sfc: maintain management event queue
> net/sfc: periodic management EVQ polling using alarm
> net/sfc: minimum port control sufficient to receive traffic
> net/sfc: implement Rx subsystem stubs
> net/sfc: check configured rxmode
> net/sfc: implement Rx queue setup release operations
> net/sfc: calculate Rx buffer size which may be used
> net/sfc: validate Rx queue buffers setup
> net/sfc: implement Rx queue start and stop operations
> net/sfc: implement device callback to Rx burst of packets
> net/sfc: discard scattered packet on Rx correctly
>
> Artem Andreev (2):
> net/sfc: include libefx in build
> net/sfc: implement device operation to retrieve link info
>
> Ivan Malov (5):
> net/sfc: provide basic stubs for Tx subsystem
> net/sfc: add function to check configured Tx mode
> net/sfc: add callbacks to set up and release Tx queues
> net/sfc: implement transmit path start / stop
> net/sfc: add callback to send bursts of packets
>
Series Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
^ permalink raw reply
* Re: [PATCH] Scheduler: add driver for scheduler crypto pmd
From: Bruce Richardson @ 2016-12-02 14:57 UTC (permalink / raw)
To: Thomas Monjalon; +Cc: Fan Zhang, dev, declan.doherty
In-Reply-To: <8047937.9v81RFizFU@xps13>
On Fri, Dec 02, 2016 at 03:31:24PM +0100, Thomas Monjalon wrote:
> 2016-12-02 14:15, Fan Zhang:
> > This patch provides the initial implementation of the scheduler poll mode
> > driver using DPDK cryptodev framework.
> >
> > Scheduler PMD is used to schedule and enqueue the crypto ops to the
> > hardware and/or software crypto devices attached to it (slaves). The
> > dequeue operation from the slave(s), and the possible dequeued crypto op
> > reordering, are then carried out by the scheduler.
> >
> > The scheduler PMD can be used to fill the throughput gap between the
> > physical core and the existing cryptodevs to increase the overall
> > performance. For example, if a physical core has higher crypto op
> > processing rate than a cryptodev, the scheduler PMD can be introduced to
> > attach more than one cryptodevs.
> >
> > This initial implementation is limited to supporting the following
> > scheduling modes:
> >
> > - CRYPTO_SCHED_SW_ROUND_ROBIN_MODE (round robin amongst attached software
> > slave cryptodevs, to set this mode, the scheduler should have been
> > attached 1 or more software cryptodevs.
> >
> > - CRYPTO_SCHED_HW_ROUND_ROBIN_MODE (round robin amongst attached hardware
> > slave cryptodevs (QAT), to set this mode, the scheduler should have
> > been attached 1 or more QATs.
>
> Could it be implemented on top of the eventdev API?
>
Not really. The eventdev API is for different types of scheduling
between multiple sources that are all polling for packets, compared to
this, which is more analgous - as I understand it - to the bonding PMD
for ethdev.
To make something like this work with an eventdev API you would need to
use one of the following models:
* have worker cores for offloading packets to the different crypto
blocks pulling from the eventdev APIs. This would make it difficult to
do any "smart" scheduling of crypto operations between the blocks,
e.g. that one crypto instance may be better at certain types of
operations than another.
* move the logic in this driver into an existing eventdev instance,
which uses the eventdev api rather than the crypto APIs and so has an
extra level of "structure abstraction" that has to be worked though.
It's just not really a good fit.
So for this workload, I believe the pseudo-cryptodev instance is the
best way to go.
/Bruce
^ permalink raw reply
* Re: [PATCH v2 01/55] net/sfc: libefx-based PMD stub sufficient to build and init
From: Andrew Rybchenko @ 2016-12-02 15:03 UTC (permalink / raw)
To: Ferruh Yigit, dev
In-Reply-To: <1e5503bf-8150-a4db-fd16-8c3e4c8e9737@intel.com>
On 12/02/2016 05:54 PM, Ferruh Yigit wrote:
> On 11/29/2016 4:18 PM, Andrew Rybchenko wrote:
>> The PMD is put into the sfc/efx subdirectory to have a place for
> .. into sfc subdirectory ..
>
>> the second PMD and library shared by both.
> Since all will go into same (sfc) folder, should mention from this? This
> looks like justification of previous sfc/efx.
I think it should go away now since we have no efx subdirectory.
It was necessary to explain unusual structure, but right now we have usual
structure. Should I send v3 or will you simply remove it before pushing?
Thanks for noticing it,
Andrew.
>> Enable the PMD by default on supported configuratons.
>>
>> Reviewed-by: Andy Moreton <amoreton@solarflare.com>
>> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
>> ---
^ permalink raw reply
* Re: [PATCH v2 01/55] net/sfc: libefx-based PMD stub sufficient to build and init
From: Ferruh Yigit @ 2016-12-02 15:08 UTC (permalink / raw)
To: Andrew Rybchenko, dev
In-Reply-To: <27521ea0-8151-311f-1889-16fcb30d217a@solarflare.com>
On 12/2/2016 3:03 PM, Andrew Rybchenko wrote:
> On 12/02/2016 05:54 PM, Ferruh Yigit wrote:
>> On 11/29/2016 4:18 PM, Andrew Rybchenko wrote:
>>> The PMD is put into the sfc/efx subdirectory to have a place for
>> .. into sfc subdirectory ..
>>
>>> the second PMD and library shared by both.
>> Since all will go into same (sfc) folder, should mention from this? This
>> looks like justification of previous sfc/efx.
>
> I think it should go away now since we have no efx subdirectory.
> It was necessary to explain unusual structure, but right now we have usual
> structure. Should I send v3 or will you simply remove it before pushing?
>
No new version required just for this, I can fix while applying. Can you
confirm following commit log:
"
Enable the PMD by default on supported configurations.
Reviewed-by: Andy Moreton <amoreton@solarflare.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
"
Thanks,
ferruh
^ permalink raw reply
* Re: [PATCH v2 01/55] net/sfc: libefx-based PMD stub sufficient to build and init
From: Andrew Rybchenko @ 2016-12-02 15:11 UTC (permalink / raw)
To: Ferruh Yigit, dev
In-Reply-To: <146ed7f3-0452-7a4b-aab8-893e039964c0@intel.com>
On 12/02/2016 06:08 PM, Ferruh Yigit wrote:
> On 12/2/2016 3:03 PM, Andrew Rybchenko wrote:
>> On 12/02/2016 05:54 PM, Ferruh Yigit wrote:
>>> On 11/29/2016 4:18 PM, Andrew Rybchenko wrote:
>>>> The PMD is put into the sfc/efx subdirectory to have a place for
>>> .. into sfc subdirectory ..
>>>
>>>> the second PMD and library shared by both.
>>> Since all will go into same (sfc) folder, should mention from this? This
>>> looks like justification of previous sfc/efx.
>> I think it should go away now since we have no efx subdirectory.
>> It was necessary to explain unusual structure, but right now we have usual
>> structure. Should I send v3 or will you simply remove it before pushing?
>>
> No new version required just for this, I can fix while applying. Can you
> confirm following commit log:
>
> "
> Enable the PMD by default on supported configurations.
>
> Reviewed-by: Andy Moreton <amoreton@solarflare.com>
> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
> "
Confirmed.
Thanks,
Andrew.
^ permalink raw reply
* [PATCH 0/2] Introduce new performance test application
From: Michal Jastrzebski @ 2016-12-02 15:15 UTC (permalink / raw)
To: dev; +Cc: pablo.de.lara.guarch
This patchset introduce new application which allows measuring
performance parameters of PMDs available in crypto tree. The goal of
this application is to replace existing performance tests in app/test.
Parameters available are: throughput (--ptest throughput) and latency
(--ptest latency). User can use multiply cores to run tests on but only
one type of crypto PMD can be measured during single application
execution. Cipher parameters, type of device, type of operation and
chain mode have to be specified in the command line as application
parameters. These parameters are checked using device capabilities
structure.
Couple of new library functions in librte_cryptodev are introduced for
application use.
To build the application a CONFIG_RTE_APP_CRYPTO_PERF flag has to be set
(it is set by default).
Example of usage: -c 0xc0 --vdev crypto_aesni_mb_pmd -w 0000:00:00.0 --
--ptest throughput --devtype crypto_aesni_mb --optype cipher-then-auth
--cipher-algo aes-cbc --cipher-op encrypt --cipher-key-sz 16 --auth-algo
sha1-hmac --auth-op generate --auth-key-sz 64 --auth-digest-sz 12
--total-ops 10000000 --burst-sz 32 --buffer-sz 64
There are some work planned to be completed later in this release:
- --nb-segments param – additional flag for measuring performance when
chained mbufs are processing in crypto device. “param” specify number of
mbuf segments.
- --verify test_vectors_file – if user wants the cryptography
correctness to be verified, he needs to turn on “verify” flag and needs
to specify an input file with test_vectors.
- Simplify application output to allow output to be easily
consumed by a script or copied into excel.
- Create script to create algorithm performance matrix for PMDs.
Declan Doherty (2):
lib/librte_cryptodev: functions for new performance test application
app/crypto-perf: Introduce new performance test application
app/Makefile | 1 +
app/crypto-perf/Makefile | 52 +++
app/crypto-perf/cperf.h | 58 +++
app/crypto-perf/cperf_ops.c | 424 +++++++++++++++++++
app/crypto-perf/cperf_ops.h | 67 +++
app/crypto-perf/cperf_options.h | 95 +++++
app/crypto-perf/cperf_options_parsing.c | 695 +++++++++++++++++++++++++++++++
app/crypto-perf/cperf_test_latency.c | 455 ++++++++++++++++++++
app/crypto-perf/cperf_test_latency.h | 57 +++
app/crypto-perf/cperf_test_throughput.c | 433 +++++++++++++++++++
app/crypto-perf/cperf_test_throughput.h | 58 +++
app/crypto-perf/cperf_test_vectors.c | 339 +++++++++++++++
app/crypto-perf/cperf_test_vectors.h | 110 +++++
app/crypto-perf/cperf_vectors_all.c | 238 +++++++++++
app/crypto-perf/main.c | 291 +++++++++++++
config/common_base | 6 +
lib/librte_cryptodev/rte_crypto_sym.h | 16 +
lib/librte_cryptodev/rte_cryptodev.c | 177 ++++++++
lib/librte_cryptodev/rte_cryptodev.h | 120 ++++--
19 files changed, 3646 insertions(+), 46 deletions(-)
create mode 100644 app/crypto-perf/Makefile
create mode 100644 app/crypto-perf/cperf.h
create mode 100644 app/crypto-perf/cperf_ops.c
create mode 100644 app/crypto-perf/cperf_ops.h
create mode 100644 app/crypto-perf/cperf_options.h
create mode 100644 app/crypto-perf/cperf_options_parsing.c
create mode 100644 app/crypto-perf/cperf_test_cyclecount.c
create mode 100644 app/crypto-perf/cperf_test_latency.c
create mode 100644 app/crypto-perf/cperf_test_latency.h
create mode 100644 app/crypto-perf/cperf_test_throughput.c
create mode 100644 app/crypto-perf/cperf_test_throughput.h
create mode 100644 app/crypto-perf/cperf_test_vectors.c
create mode 100644 app/crypto-perf/cperf_test_vectors.h
create mode 100644 app/crypto-perf/cperf_vectors_all.c
create mode 100644 app/crypto-perf/main.c
--
1.7.9.5
^ permalink raw reply
* [PATCH 1/2] lib/librte_cryptodev: functions for new performance test application
From: Michal Jastrzebski @ 2016-12-02 15:15 UTC (permalink / raw)
To: dev; +Cc: pablo.de.lara.guarch, Declan Doherty, Slawomir Mrozowicz,
Marcin Kerlin
In-Reply-To: <1480691702-4600-1-git-send-email-michalx.k.jastrzebski@intel.com>
This patch adds helper functions for new performance application.
Application can be used to measute throughput and latency of
cryptography operation performed by crypto device.
Signed-off-by: Declan Doherty <declan.doherty@intel.com>
Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Marcin Kerlin <marcinx.kerlin@intel.com>
---
lib/librte_cryptodev/rte_crypto_sym.h | 16 +++
lib/librte_cryptodev/rte_cryptodev.c | 177 +++++++++++++++++++++++++++++++++
lib/librte_cryptodev/rte_cryptodev.h | 120 +++++++++++++---------
3 files changed, 267 insertions(+), 46 deletions(-)
diff --git a/lib/librte_cryptodev/rte_crypto_sym.h b/lib/librte_cryptodev/rte_crypto_sym.h
index d3d38e4..e905ad6 100644
--- a/lib/librte_cryptodev/rte_crypto_sym.h
+++ b/lib/librte_cryptodev/rte_crypto_sym.h
@@ -108,6 +108,10 @@ enum rte_crypto_cipher_algorithm {
RTE_CRYPTO_CIPHER_LIST_END
};
+/** Cipher algorithm name strings */
+extern const char *
+rte_crypto_cipher_algorithm_strings[];
+
/** Symmetric Cipher Direction */
enum rte_crypto_cipher_operation {
RTE_CRYPTO_CIPHER_OP_ENCRYPT,
@@ -116,6 +120,10 @@ enum rte_crypto_cipher_operation {
/**< Decrypt cipher operation */
};
+/** Cipher operation name strings */
+extern const char *
+rte_crypto_cipher_operation_strings[];
+
/**
* Symmetric Cipher Setup Data.
*
@@ -241,12 +249,20 @@ enum rte_crypto_auth_algorithm {
RTE_CRYPTO_AUTH_LIST_END
};
+/** Authentication algorithm name strings */
+extern const char *
+rte_crypto_auth_algorithm_strings[];
+
/** Symmetric Authentication / Hash Operations */
enum rte_crypto_auth_operation {
RTE_CRYPTO_AUTH_OP_VERIFY, /**< Verify authentication digest */
RTE_CRYPTO_AUTH_OP_GENERATE /**< Generate authentication digest */
};
+/** Authentication operation name strings */
+extern const char *
+rte_crypto_auth_operation_strings[];
+
/**
* Authentication / Hash transform data.
*
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 127e8d0..af0e554 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -111,6 +111,86 @@ struct rte_cryptodev_callback {
RTE_CRYPTODEV_VDEV_SOCKET_ID
};
+/**
+ * The crypto cipher algorithm strings identifiers.
+ * It could be used in application command line.
+ */
+const char *
+rte_crypto_cipher_algorithm_strings[] = {
+ [RTE_CRYPTO_CIPHER_3DES_CBC] = "3des-cbc",
+ [RTE_CRYPTO_CIPHER_3DES_ECB] = "3des-ecb",
+ [RTE_CRYPTO_CIPHER_3DES_CTR] = "3des-ctr",
+
+ [RTE_CRYPTO_CIPHER_AES_CBC] = "aes-cbc",
+ [RTE_CRYPTO_CIPHER_AES_CCM] = "aes-ccm",
+ [RTE_CRYPTO_CIPHER_AES_CTR] = "aes-ctr",
+ [RTE_CRYPTO_CIPHER_AES_ECB] = "aes-ecb",
+ [RTE_CRYPTO_CIPHER_AES_GCM] = "aes-gcm",
+ [RTE_CRYPTO_CIPHER_AES_F8] = "aes-f8",
+ [RTE_CRYPTO_CIPHER_AES_XTS] = "aes-xts",
+
+ [RTE_CRYPTO_CIPHER_ARC4] = "arc4",
+
+ [RTE_CRYPTO_CIPHER_NULL] = "null",
+
+ [RTE_CRYPTO_CIPHER_KASUMI_F8] = "kasumi-f8",
+ [RTE_CRYPTO_CIPHER_SNOW3G_UEA2] = "snow3g-uea2",
+ [RTE_CRYPTO_CIPHER_ZUC_EEA3] = "zuc-eea3"
+};
+
+/**
+ * The crypto cipher operation strings identifiers.
+ * It could be used in application command line.
+ */
+const char *
+rte_crypto_cipher_operation_strings[] = {
+ [RTE_CRYPTO_CIPHER_OP_ENCRYPT] = "encrypt",
+ [RTE_CRYPTO_CIPHER_OP_DECRYPT] = "decrypt"
+};
+
+/**
+ * The crypto auth algorithm strings identifiers.
+ * It could be used in application command line.
+ */
+const char *
+rte_crypto_auth_algorithm_strings[] = {
+ [RTE_CRYPTO_AUTH_AES_CBC_MAC] = "aes-cbc-mac",
+ [RTE_CRYPTO_AUTH_AES_CCM] = "aes-ccm",
+ [RTE_CRYPTO_AUTH_AES_CMAC] = "aes-cmac",
+ [RTE_CRYPTO_AUTH_AES_GCM] = "aes-gcm",
+ [RTE_CRYPTO_AUTH_AES_GMAC] = "aes-gmac",
+ [RTE_CRYPTO_AUTH_AES_XCBC_MAC] = "aes-xcbc-mac",
+
+ [RTE_CRYPTO_AUTH_MD5] = "md5",
+ [RTE_CRYPTO_AUTH_MD5_HMAC] = "md5-hmac",
+
+ [RTE_CRYPTO_AUTH_SHA1] = "sha1",
+ [RTE_CRYPTO_AUTH_SHA1_HMAC] = "sha1-hmac",
+
+ [RTE_CRYPTO_AUTH_SHA224] = "sha2-224",
+ [RTE_CRYPTO_AUTH_SHA224_HMAC] = "sha2-224-hmac",
+ [RTE_CRYPTO_AUTH_SHA256] = "sha2-256",
+ [RTE_CRYPTO_AUTH_SHA256_HMAC] = "sha2-256-hmac",
+ [RTE_CRYPTO_AUTH_SHA384] = "sha2-384",
+ [RTE_CRYPTO_AUTH_SHA384_HMAC] = "sha2-384-hmac",
+ [RTE_CRYPTO_AUTH_SHA512] = "sha2-512",
+ [RTE_CRYPTO_AUTH_SHA512_HMAC] = "sha2-512-hmac",
+
+ [RTE_CRYPTO_AUTH_KASUMI_F9] = "kasumi-f9",
+ [RTE_CRYPTO_AUTH_SNOW3G_UIA2] = "snow3g-uia2",
+ [RTE_CRYPTO_AUTH_ZUC_EIA3] = "zuc-eia3"
+};
+
+/**
+ * The crypto auth operation strings identifiers.
+ * It could be used in application command line.
+ */
+const char *
+rte_crypto_auth_operation_strings[] = {
+ [RTE_CRYPTO_AUTH_OP_VERIFY] = "verify",
+ [RTE_CRYPTO_AUTH_OP_GENERATE] = "generate"
+};
+
static uint8_t
number_of_sockets(void)
{
@@ -191,6 +271,75 @@ struct rte_cryptodev_callback {
return ret;
}
+const struct rte_cryptodev_symmetric_capability *
+rte_cryptodev_capbility_get(uint8_t dev_id,
+ const struct rte_cryptodev_capbility_idx *idx)
+{
+ const struct rte_cryptodev_capabilities *capability;
+ struct rte_cryptodev_info dev_info;
+ int i;
+
+ rte_cryptodev_info_get(dev_id, &dev_info);
+
+ i = 0;
+
+ while ((capability = &dev_info.capabilities[i++])->op !=
+ RTE_CRYPTO_OP_TYPE_UNDEFINED) {
+ if (capability->op != RTE_CRYPTO_OP_TYPE_SYMMETRIC)
+ continue;
+
+ if (capability->sym.xform_type != idx->type)
+ continue;
+
+ if (idx->type == RTE_CRYPTO_SYM_XFORM_AUTH &&
+ capability->sym.auth.algo == idx->algo.auth)
+ return &capability->sym;
+
+ if (idx->type == RTE_CRYPTO_SYM_XFORM_CIPHER &&
+ capability->sym.cipher.algo == idx->algo.cipher)
+ return &capability->sym;
+ }
+
+ return NULL;
+
+}
+
+#define param_range_check(x, y) \
+ (((x < y.min && y.min != -1) || (x > y.max && y.min != -1)) || \
+ ((y.increment != -1) && (y.increment != 0 && (x % y.increment) != 0)))
+
+int
+rte_cryptodev_capability_check_cipher(
+ const struct rte_cryptodev_symmetric_capability *capability,
+ uint16_t key_size, uint16_t iv_size)
+{
+ if (param_range_check(key_size, capability->cipher.key_size))
+ return -1;
+
+ if (param_range_check(iv_size, capability->cipher.iv_size))
+ return -1;
+
+ return 0;
+}
+
+int
+rte_cryptodev_capability_check_auth(
+ const struct rte_cryptodev_symmetric_capability *capability,
+ uint16_t key_size, uint16_t digest_size, uint16_t aad_size)
+{
+ if (param_range_check(key_size, capability->auth.key_size))
+ return -1;
+
+ if (param_range_check(digest_size, capability->auth.digest_size))
+ return -1;
+
+ if (param_range_check(aad_size, capability->auth.aad_size))
+ return -1;
+
+ return 0;
+}
+
+
const char *
rte_cryptodev_get_feature_name(uint64_t flag)
{
@@ -262,6 +411,34 @@ struct rte_cryptodev_callback {
}
int
+rte_cryptodev_devices_get(const char *drv_name, uint8_t *devices,
+ uint8_t nb_devices)
+{
+ uint8_t i, cmp, count = 0;
+ struct rte_cryptodev **devs = &rte_cryptodev_globals->devs;
+
+ for (i = 0; i < rte_cryptodev_globals->max_devs && count < nb_devices;
+ i++) {
+
+ if ((*devs + i)
+ && (*devs + i)->attached == RTE_CRYPTODEV_ATTACHED) {
+
+ if ((*devs + i)->pci_dev)
+ cmp = strncmp((*devs + i)->pci_dev->driver->driver.name,
+ drv_name, strlen(drv_name));
+ else
+ cmp = strncmp((*devs + i)->data->name, drv_name,
+ strlen(drv_name));
+
+ if (cmp == 0)
+ devices[count++] = (*devs + i)->data->dev_id;
+ }
+ }
+
+ return count;
+}
+
+int
rte_cryptodev_socket_id(uint8_t dev_id)
{
struct rte_cryptodev *dev;
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 8f63e8f..43041df 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -76,7 +76,7 @@ enum rte_cryptodev_type {
RTE_CRYPTODEV_SNOW3G_PMD, /**< SNOW 3G PMD */
RTE_CRYPTODEV_KASUMI_PMD, /**< KASUMI PMD */
RTE_CRYPTODEV_ZUC_PMD, /**< ZUC PMD */
- RTE_CRYPTODEV_OPENSSL_PMD, /**< OpenSSL PMD */
+ RTE_CRYPTODEV_OPENSSL_PMD, /**< OpenSSL PMD */
};
extern const char **rte_cyptodev_names;
@@ -110,6 +110,20 @@ enum rte_cryptodev_type {
#endif
/**
+ * Crypto parameters range description
+ */
+struct rte_crypto_param_range {
+ int min; /**< minimum size */
+ int max; /**< maximum size */
+ int increment;
+ /**< if a range of sizes are supported,
+ * this parameter is used to indicate
+ * increments in byte size that are supported
+ * between the minimum and maximum
+ */
+};
+
+/**
* Symmetric Crypto Capability
*/
struct rte_cryptodev_symmetric_capability {
@@ -122,35 +136,11 @@ struct rte_cryptodev_symmetric_capability {
/**< authentication algorithm */
uint16_t block_size;
/**< algorithm block size */
- struct {
- uint16_t min; /**< minimum key size */
- uint16_t max; /**< maximum key size */
- uint16_t increment;
- /**< if a range of sizes are supported,
- * this parameter is used to indicate
- * increments in byte size that are supported
- * between the minimum and maximum */
- } key_size;
+ struct rte_crypto_param_range key_size;
/**< auth key size range */
- struct {
- uint16_t min; /**< minimum digest size */
- uint16_t max; /**< maximum digest size */
- uint16_t increment;
- /**< if a range of sizes are supported,
- * this parameter is used to indicate
- * increments in byte size that are supported
- * between the minimum and maximum */
- } digest_size;
+ struct rte_crypto_param_range digest_size;
/**< digest size range */
- struct {
- uint16_t min; /**< minimum aad size */
- uint16_t max; /**< maximum aad size */
- uint16_t increment;
- /**< if a range of sizes are supported,
- * this parameter is used to indicate
- * increments in byte size that are supported
- * between the minimum and maximum */
- } aad_size;
+ struct rte_crypto_param_range aad_size;
/**< Additional authentication data size range */
} auth;
/**< Symmetric Authentication transform capabilities */
@@ -159,25 +149,9 @@ struct rte_cryptodev_symmetric_capability {
/**< cipher algorithm */
uint16_t block_size;
/**< algorithm block size */
- struct {
- uint16_t min; /**< minimum key size */
- uint16_t max; /**< maximum key size */
- uint16_t increment;
- /**< if a range of sizes are supported,
- * this parameter is used to indicate
- * increments in byte size that are supported
- * between the minimum and maximum */
- } key_size;
+ struct rte_crypto_param_range key_size;
/**< cipher key size range */
- struct {
- uint16_t min; /**< minimum iv size */
- uint16_t max; /**< maximum iv size */
- uint16_t increment;
- /**< if a range of sizes are supported,
- * this parameter is used to indicate
- * increments in byte size that are supported
- * between the minimum and maximum */
- } iv_size;
+ struct rte_crypto_param_range iv_size;
/**< Initialisation vector data size range */
} cipher;
/**< Symmetric Cipher transform capabilities */
@@ -196,6 +170,38 @@ struct rte_cryptodev_capabilities {
};
};
+/** Structure used to describe crypto algorithms */
+struct rte_cryptodev_capbility_idx {
+ enum rte_crypto_sym_xform_type type;
+ union {
+ enum rte_crypto_cipher_algorithm cipher;
+ enum rte_crypto_auth_algorithm auth;
+ } algo;
+};
+
+/** Provide capabilities available for defined device and algorithm */
+const struct rte_cryptodev_symmetric_capability *
+rte_cryptodev_capbility_get(uint8_t dev_id,
+ const struct rte_cryptodev_capbility_idx *idx);
+
+/**
+ * Check if key size and initial vector are supported
+ * in crypto cipher capability
+ */
+int
+rte_cryptodev_capability_check_cipher(
+ const struct rte_cryptodev_symmetric_capability *capability,
+ uint16_t key_size, uint16_t iv_size);
+
+/**
+ * Check if key size and initial vector are supported
+ * in crypto auth capability
+ */
+int
+rte_cryptodev_capability_check_auth(
+ const struct rte_cryptodev_symmetric_capability *capability,
+ uint16_t key_size, uint16_t digest_size, uint16_t aad_size);
+
/** Macro used at end of crypto PMD list */
#define RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST() \
{ RTE_CRYPTO_OP_TYPE_UNDEFINED }
@@ -365,8 +371,30 @@ struct rte_crypto_vdev_init_params {
extern uint8_t
rte_cryptodev_count(void);
+/**
+ * Get number of crypto device defined type.
+ *
+ * @param type type of device.
+ *
+ * @return
+ * Returns number of crypto device.
+ */
extern uint8_t
rte_cryptodev_count_devtype(enum rte_cryptodev_type type);
+
+/**
+ * Get number and identifiers of attached crypto device.
+ *
+ * @param drv_name device name.
+ * @param devices output devices identifiers.
+ * @param nb_devices maximal number of devices.
+ *
+ * @return
+ * Returns number of attached crypto device.
+ */
+int
+rte_cryptodev_devices_get(const char *drv_name, uint8_t *devices,
+ uint8_t nb_devices);
/*
* Return the NUMA socket to which a device is connected
*
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/2] app/crypto-perf: Introduce new performance test application
From: Michal Jastrzebski @ 2016-12-02 15:15 UTC (permalink / raw)
To: dev
Cc: pablo.de.lara.guarch, Declan Doherty, Slawomir Mrozowicz,
Piotr Azarewicz
In-Reply-To: <1480691702-4600-1-git-send-email-michalx.k.jastrzebski@intel.com>
This patchset introduce new application which allows measuring
performance parameters of PMDs available in crypto tree. The goal of
this application is to replace existing performance tests in app/test.
Parameters available are: throughput (--ptest throughput) and latency
(--ptest latency). User can use multiply cores to run tests on but only
one type of crypto PMD can be measured during single application
execution. Cipher parameters, type of device, type of operation and
chain mode have to be specified in the command line as application
parameters. These parameters are checked using device capabilities
structure.
Couple of new library functions in librte_cryptodev are introduced for
application use.
To build the application a CONFIG_RTE_APP_CRYPTO_PERF flag has to be set
(it is set by default).
Example of usage: -c 0xc0 --vdev crypto_aesni_mb_pmd -w 0000:00:00.0 --
--ptest throughput --devtype crypto_aesni_mb --optype cipher-then-auth
--cipher-algo aes-cbc --cipher-op encrypt --cipher-key-sz 16 --auth-algo
sha1-hmac --auth-op generate --auth-key-sz 64 --auth-digest-sz 12
--total-ops 10000000 --burst-sz 32 --buffer-sz 64
There are some work planned to be completed later in this release:
- --nb-segments param – additional flag for measuring performance when
chained mbufs are processing in crypto device. “param” specify number of
mbuf segments.
- --verify test_vectors_file – if user wants the cryptography
correctness to be verified, he needs to turn on “verify” flag and needs
to specify an input file with test_vectors.
- Simplify application output to allow output to be easily
consumed by a script or copied into excel.
- Create script to create algorithm performance matrix for PMDs.
Signed-off-by: Declan Doherty <declan.doherty@intel.com>
Signed-off-by: Slawomir Mrozowicz <slawomirx.mrozowicz@intel.com>
Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
---
app/Makefile | 1 +
app/crypto-perf/Makefile | 52 +++
app/crypto-perf/cperf.h | 58 +++
app/crypto-perf/cperf_ops.c | 424 +++++++++++++++++++
app/crypto-perf/cperf_ops.h | 67 +++
app/crypto-perf/cperf_options.h | 95 +++++
app/crypto-perf/cperf_options_parsing.c | 695 +++++++++++++++++++++++++++++++
app/crypto-perf/cperf_test_latency.c | 455 ++++++++++++++++++++
app/crypto-perf/cperf_test_latency.h | 57 +++
app/crypto-perf/cperf_test_throughput.c | 433 +++++++++++++++++++
app/crypto-perf/cperf_test_throughput.h | 58 +++
app/crypto-perf/cperf_test_vectors.c | 339 +++++++++++++++
app/crypto-perf/cperf_test_vectors.h | 110 +++++
app/crypto-perf/cperf_vectors_all.c | 238 +++++++++++
app/crypto-perf/main.c | 291 +++++++++++++
config/common_base | 6 +
16 files changed, 3379 insertions(+)
create mode 100644 app/crypto-perf/Makefile
create mode 100644 app/crypto-perf/cperf.h
create mode 100644 app/crypto-perf/cperf_ops.c
create mode 100644 app/crypto-perf/cperf_ops.h
create mode 100644 app/crypto-perf/cperf_options.h
create mode 100644 app/crypto-perf/cperf_options_parsing.c
create mode 100644 app/crypto-perf/cperf_test_cyclecount.c
create mode 100644 app/crypto-perf/cperf_test_latency.c
create mode 100644 app/crypto-perf/cperf_test_latency.h
create mode 100644 app/crypto-perf/cperf_test_throughput.c
create mode 100644 app/crypto-perf/cperf_test_throughput.h
create mode 100644 app/crypto-perf/cperf_test_vectors.c
create mode 100644 app/crypto-perf/cperf_test_vectors.h
create mode 100644 app/crypto-perf/cperf_vectors_all.c
create mode 100644 app/crypto-perf/main.c
diff --git a/app/Makefile b/app/Makefile
index 30ec292..8cf43cb 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -38,5 +38,6 @@ DIRS-$(CONFIG_RTE_TEST_PMD) += test-pmd
DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_test
DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += proc_info
DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += pdump
+DIRS-$(CONFIG_RTE_APP_CRYPTO_PERF) += crypto-perf
include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/app/crypto-perf/Makefile b/app/crypto-perf/Makefile
new file mode 100644
index 0000000..d96b9f6
--- /dev/null
+++ b/app/crypto-perf/Makefile
@@ -0,0 +1,52 @@
+# 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
+
+
+APP = crypto-perf
+
+CFLAGS += $(WERROR_FLAGS)
+
+# all source are stored in SRCS-y
+
+SRCS-y := main.c
+SRCS-y += cperf_ops.c
+SRCS-y += cperf_options_parsing.c
+SRCS-y += cperf_test_vectors.c
+SRCS-y += cperf_vectors_all.c
+SRCS-y += cperf_test_throughput.c
+SRCS-y += cperf_test_latency.c
+
+# this application needs libraries first
+DEPDIRS-y += lib
+
+include $(RTE_SDK)/mk/rte.app.mk
+
diff --git a/app/crypto-perf/cperf.h b/app/crypto-perf/cperf.h
new file mode 100644
index 0000000..8509dd0
--- /dev/null
+++ b/app/crypto-perf/cperf.h
@@ -0,0 +1,58 @@
+/*-
+ * 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 _CPERF_
+#define _CPERF_
+
+#include <rte_crypto.h>
+
+#include "cperf_ops.h"
+
+struct cperf_options;
+struct cperf_test_vector;
+struct cperf_op_fns;
+
+typedef void *(*cperf_constructor_t)(uint8_t dev_id, uint16_t qp_id,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *t_vec,
+ const struct cperf_op_fns *op_fns);
+
+typedef int (*cperf_runner_t)(void *test_ctx);
+typedef void (*cperf_destructor_t)(void *test_ctx);
+
+struct cperf_test {
+ cperf_constructor_t constructor;
+ cperf_runner_t runner;
+ cperf_destructor_t desctructor;
+};
+
+#endif /* _CPERF_ */
diff --git a/app/crypto-perf/cperf_ops.c b/app/crypto-perf/cperf_ops.c
new file mode 100644
index 0000000..7a3dca8
--- /dev/null
+++ b/app/crypto-perf/cperf_ops.c
@@ -0,0 +1,424 @@
+#include <rte_cryptodev.h>
+
+#include "cperf_ops.h"
+#include "cperf_test_vectors.h"
+
+static int
+cperf_set_ops_null_cipher(struct rte_crypto_op **ops,
+ struct rte_mbuf **bufs, uint16_t nb_ops,
+ struct rte_cryptodev_sym_session *sess,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector __rte_unused)
+{
+ uint16_t i;
+
+ for (i = 0; i < nb_ops; i++) {
+ struct rte_crypto_sym_op *sym_op = ops[i]->sym;
+
+ rte_crypto_op_attach_sym_session(ops[i], sess);
+
+ sym_op->m_src = bufs[i];
+
+ /* cipher parameters */
+ sym_op->cipher.data.length = options->buffer_sz;
+ sym_op->cipher.data.offset = 0;
+ }
+
+ return 0;
+}
+
+static int
+cperf_set_ops_null_auth(struct rte_crypto_op **ops,
+ struct rte_mbuf **bufs, uint16_t nb_ops,
+ struct rte_cryptodev_sym_session *sess,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector __rte_unused)
+{
+ uint16_t i;
+
+ for (i = 0; i < nb_ops; i++) {
+ struct rte_crypto_sym_op *sym_op = ops[i]->sym;
+
+ rte_crypto_op_attach_sym_session(ops[i], sess);
+
+ sym_op->m_src = bufs[i];
+
+ /* auth parameters */
+ sym_op->auth.data.length = options->buffer_sz;
+ sym_op->auth.data.offset = 0;
+ }
+
+ return 0;
+}
+
+static int
+cperf_set_ops_cipher(struct rte_crypto_op **ops,
+ struct rte_mbuf **bufs, uint16_t nb_ops,
+ struct rte_cryptodev_sym_session *sess,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector)
+{
+ uint16_t i;
+
+ for (i = 0; i < nb_ops; i++) {
+ struct rte_crypto_sym_op *sym_op = ops[i]->sym;
+
+ rte_crypto_op_attach_sym_session(ops[i], sess);
+
+ sym_op->m_src = bufs[i];
+
+ /* cipher parameters */
+ sym_op->cipher.iv.data = test_vector->iv.data;
+ sym_op->cipher.iv.phys_addr = test_vector->iv.phys_addr;
+ sym_op->cipher.iv.length = test_vector->iv.length;
+
+ sym_op->cipher.data.length = options->buffer_sz;
+ sym_op->cipher.data.offset = 0;
+ }
+
+ return 0;
+}
+
+static int
+cperf_set_ops_auth(struct rte_crypto_op **ops,
+ struct rte_mbuf **bufs, uint16_t nb_ops,
+ struct rte_cryptodev_sym_session *sess,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector)
+{
+ uint16_t i;
+
+ for (i = 0; i < nb_ops; i++) {
+ struct rte_crypto_sym_op *sym_op = ops[i]->sym;
+
+ rte_crypto_op_attach_sym_session(ops[i], sess);
+
+ sym_op->m_src = bufs[i];
+
+ /* authentication parameters */
+ if (options->auth_op == RTE_CRYPTO_AUTH_OP_VERIFY) {
+ sym_op->auth.digest.data = test_vector->digest.data;
+ sym_op->auth.digest.phys_addr =
+ test_vector->digest.phys_addr;
+ sym_op->auth.digest.length = options->auth_digest_sz;
+ } else {
+
+ uint32_t offset = options->buffer_sz;
+ struct rte_mbuf *buf = bufs[i];
+
+ while ((buf->next != NULL) &&
+ (offset >= buf->data_len)) {
+ offset -= buf->data_len;
+ buf = buf->next;
+ }
+
+ sym_op->auth.digest.data = rte_pktmbuf_mtod_offset(buf,
+ uint8_t *, offset);
+ sym_op->auth.digest.phys_addr =
+ rte_pktmbuf_mtophys_offset(buf, offset);
+ sym_op->auth.digest.length = options->auth_digest_sz;
+ sym_op->auth.aad.phys_addr = test_vector->aad.phys_addr;
+ sym_op->auth.aad.data = test_vector->aad.data;
+ sym_op->auth.aad.length = options->auth_aad_sz;
+
+ }
+
+ sym_op->auth.data.length = options->buffer_sz;
+ sym_op->auth.data.offset = 0;
+ }
+
+ return 0;
+}
+
+static int
+cperf_set_ops_cipher_auth(struct rte_crypto_op **ops,
+ struct rte_mbuf **bufs, uint16_t nb_ops,
+ struct rte_cryptodev_sym_session *sess,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector)
+{
+ uint16_t i;
+
+ for (i = 0; i < nb_ops; i++) {
+ struct rte_crypto_sym_op *sym_op = ops[i]->sym;
+
+ rte_crypto_op_attach_sym_session(ops[i], sess);
+
+ sym_op->m_src = bufs[i];
+
+ /* cipher parameters */
+ sym_op->cipher.iv.data = test_vector->iv.data;
+ sym_op->cipher.iv.phys_addr = test_vector->iv.phys_addr;
+ sym_op->cipher.iv.length = test_vector->iv.length;
+
+ sym_op->cipher.data.length = options->buffer_sz;
+ sym_op->cipher.data.offset = 0;
+
+ /* authentication parameters */
+ if (options->auth_op == RTE_CRYPTO_AUTH_OP_VERIFY) {
+ sym_op->auth.digest.data = test_vector->digest.data;
+ sym_op->auth.digest.phys_addr =
+ test_vector->digest.phys_addr;
+ sym_op->auth.digest.length = options->auth_digest_sz;
+ } else {
+
+ uint32_t offset = options->buffer_sz;
+ struct rte_mbuf *buf = bufs[i];
+
+ while ((buf->next != NULL) &&
+ (offset >= buf->data_len)) {
+ offset -= buf->data_len;
+ buf = buf->next;
+ }
+
+ sym_op->auth.digest.data = rte_pktmbuf_mtod_offset(buf,
+ uint8_t *, offset);
+ sym_op->auth.digest.phys_addr =
+ rte_pktmbuf_mtophys_offset(buf, offset);
+ sym_op->auth.digest.length = options->auth_digest_sz;
+ sym_op->auth.aad.phys_addr = test_vector->aad.phys_addr;
+ sym_op->auth.aad.data = test_vector->aad.data;
+ sym_op->auth.aad.length = options->auth_aad_sz;
+ }
+
+ sym_op->auth.data.length = options->buffer_sz;
+ sym_op->auth.data.offset = 0;
+ }
+
+ return 0;
+}
+
+static int
+cperf_set_ops_aead(struct rte_crypto_op **ops,
+ struct rte_mbuf **bufs, uint16_t nb_ops,
+ struct rte_cryptodev_sym_session *sess,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector)
+{
+ uint16_t i;
+
+ for (i = 0; i < nb_ops; i++) {
+ struct rte_crypto_sym_op *sym_op = ops[i]->sym;
+
+ rte_crypto_op_attach_sym_session(ops[i], sess);
+
+ sym_op->m_src = bufs[i];
+
+ /* cipher parameters */
+ sym_op->cipher.iv.data = test_vector->iv.data;
+ sym_op->cipher.iv.phys_addr = test_vector->iv.phys_addr;
+ sym_op->cipher.iv.length = test_vector->iv.length;
+
+ sym_op->cipher.data.length = options->buffer_sz;
+ sym_op->cipher.data.offset =
+ RTE_ALIGN_CEIL(options->auth_aad_sz, 16);
+
+ sym_op->auth.aad.data = rte_pktmbuf_mtod(bufs[i], uint8_t *);
+ sym_op->auth.aad.phys_addr = rte_pktmbuf_mtophys(bufs[i]);
+ sym_op->auth.aad.length = options->auth_aad_sz;
+
+ /* authentication parameters */
+ if (options->auth_op == RTE_CRYPTO_AUTH_OP_VERIFY) {
+ sym_op->auth.digest.data = test_vector->digest.data;
+ sym_op->auth.digest.phys_addr =
+ test_vector->digest.phys_addr;
+ sym_op->auth.digest.length = options->auth_digest_sz;
+ } else {
+
+ uint32_t offset = sym_op->cipher.data.length +
+ sym_op->cipher.data.offset;
+ struct rte_mbuf *buf = bufs[i];
+
+ while ((buf->next != NULL) &&
+ (offset >= buf->data_len)) {
+ offset -= buf->data_len;
+ buf = buf->next;
+ }
+
+ sym_op->auth.digest.data = rte_pktmbuf_mtod_offset(buf,
+ uint8_t *, offset);
+ sym_op->auth.digest.phys_addr =
+ rte_pktmbuf_mtophys_offset(buf, offset);
+
+ sym_op->auth.digest.length = options->auth_digest_sz;
+ }
+
+ sym_op->auth.data.length = options->buffer_sz;
+ sym_op->auth.data.offset = options->auth_aad_sz;
+ }
+
+ return 0;
+}
+
+static struct rte_cryptodev_sym_session *
+cperf_create_session(uint8_t dev_id,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector)
+{
+ struct rte_crypto_sym_xform cipher_xform;
+ struct rte_crypto_sym_xform auth_xform;
+ struct rte_cryptodev_sym_session *sess = NULL;
+
+ /*
+ * cpiher only
+ */
+ if (options->op_type == CPERF_CIPHER_ONLY) {
+ cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+ cipher_xform.next = NULL;
+ cipher_xform.cipher.algo = options->cipher_algo;
+ cipher_xform.cipher.op = options->cipher_op;
+
+ /* cipher different than null */
+ if (options->cipher_algo != RTE_CRYPTO_CIPHER_NULL) {
+ cipher_xform.cipher.key.data =
+ test_vector->cipher_key.data;
+ cipher_xform.cipher.key.length =
+ test_vector->cipher_key.length;
+ }
+ /* create crypto session */
+ sess = rte_cryptodev_sym_session_create(dev_id, &cipher_xform);
+ /*
+ * auth only
+ */
+ } else if (options->op_type == CPERF_AUTH_ONLY) {
+ auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH;
+ auth_xform.next = NULL;
+ auth_xform.auth.algo = options->auth_algo;
+ auth_xform.auth.op = options->auth_op;
+
+ /* auth different than null */
+ if (options->auth_algo != RTE_CRYPTO_AUTH_NULL) {
+ auth_xform.auth.digest_length =
+ options->auth_digest_sz;
+ auth_xform.auth.add_auth_data_length =
+ options->auth_aad_sz;
+ auth_xform.auth.key.length =
+ test_vector->auth_key.length;
+ auth_xform.auth.key.data = test_vector->auth_key.data;
+ }
+ /* create crypto session */
+ sess = rte_cryptodev_sym_session_create(dev_id, &auth_xform);
+ /*
+ * cpiher and auth
+ */
+ } else if (options->op_type == CPERF_CIPHER_THEN_AUTH ||
+ options->op_type == CPERF_AUTH_THEN_CIPHER ||
+ options->op_type == CPERF_AEAD) {
+
+ /*
+ * cipher
+ */
+ cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+ cipher_xform.next = NULL;
+ cipher_xform.cipher.algo = options->cipher_algo;
+ cipher_xform.cipher.op = options->cipher_op;
+
+ /* cipher different than null */
+ if (options->cipher_algo != RTE_CRYPTO_CIPHER_NULL) {
+ cipher_xform.cipher.key.data =
+ test_vector->cipher_key.data;
+ cipher_xform.cipher.key.length =
+ test_vector->cipher_key.length;
+ }
+
+ /*
+ * auth
+ */
+ auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH;
+ auth_xform.next = NULL;
+ auth_xform.auth.algo = options->auth_algo;
+ auth_xform.auth.op = options->auth_op;
+
+ /* auth different than null */
+ if (options->auth_algo != RTE_CRYPTO_AUTH_NULL) {
+ auth_xform.auth.digest_length = options->auth_digest_sz;
+ auth_xform.auth.add_auth_data_length =
+ options->auth_aad_sz;
+ /* auth options for aes gcm */
+ if (options->cipher_algo == RTE_CRYPTO_CIPHER_AES_GCM &&
+ options->auth_algo == RTE_CRYPTO_AUTH_AES_GCM) {
+ auth_xform.auth.key.length = 0;
+ auth_xform.auth.key.data = NULL;
+ } else { /* auth options for others */
+ auth_xform.auth.key.length =
+ test_vector->auth_key.length;
+ auth_xform.auth.key.data =
+ test_vector->auth_key.data;
+ }
+ }
+
+ /* create crypto session for aes gcm */
+ if (options->cipher_algo == RTE_CRYPTO_CIPHER_AES_GCM) {
+ if (options->cipher_op ==
+ RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
+ cipher_xform.next = &auth_xform;
+ /* create crypto session */
+ sess = rte_cryptodev_sym_session_create(dev_id,
+ &cipher_xform);
+ } else { /* decrypt */
+ auth_xform.next = &cipher_xform;
+ /* create crypto session */
+ sess = rte_cryptodev_sym_session_create(dev_id,
+ &auth_xform);
+ }
+ } else { /* create crypto session for other */
+ /* cpiher then auth */
+ if (options->op_type == CPERF_CIPHER_THEN_AUTH) {
+ cipher_xform.next = &auth_xform;
+ /* create crypto session */
+ sess = rte_cryptodev_sym_session_create(dev_id,
+ &cipher_xform);
+ } else { /* auth then cipher */
+ auth_xform.next = &cipher_xform;
+ /* create crypto session */
+ sess = rte_cryptodev_sym_session_create(dev_id,
+ &auth_xform);
+ }
+ }
+ }
+ return sess;
+}
+
+struct cperf_op_fns ops;
+
+const struct cperf_op_fns *
+cperf_get_op_functions(const struct cperf_options *options)
+{
+ ops.sess_create = cperf_create_session;
+
+ if (options->op_type == CPERF_AEAD ||
+ options->op_type == CPERF_AUTH_THEN_CIPHER ||
+ options->op_type == CPERF_CIPHER_THEN_AUTH) {
+ if (options->cipher_algo == RTE_CRYPTO_CIPHER_AES_GCM &&
+ options->auth_algo == RTE_CRYPTO_AUTH_AES_GCM) {
+ ops.populate_ops = cperf_set_ops_aead;
+ ops.verify_op = NULL;
+ } else {
+ ops.populate_ops = cperf_set_ops_cipher_auth;
+ ops.verify_op = NULL;
+ }
+ return &ops;
+ }
+ if (options->op_type == CPERF_AUTH_ONLY) {
+ if (options->auth_algo == RTE_CRYPTO_AUTH_NULL) {
+ ops.populate_ops = cperf_set_ops_null_auth;
+ ops.verify_op = NULL;
+ } else {
+ ops.populate_ops = cperf_set_ops_auth;
+ ops.verify_op = NULL;
+ }
+ return &ops;
+ }
+ if (options->op_type == CPERF_CIPHER_ONLY) {
+ if (options->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
+ ops.populate_ops = cperf_set_ops_null_cipher;
+ ops.verify_op = NULL;
+ } else {
+ ops.populate_ops = cperf_set_ops_cipher;
+ ops.verify_op = NULL;
+ }
+ return &ops;
+ }
+
+ return NULL;
+}
diff --git a/app/crypto-perf/cperf_ops.h b/app/crypto-perf/cperf_ops.h
new file mode 100644
index 0000000..bef1027
--- /dev/null
+++ b/app/crypto-perf/cperf_ops.h
@@ -0,0 +1,67 @@
+/*-
+ * 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 _CPERF_OPS_
+#define _CPERF_OPS_
+
+#include <rte_crypto.h>
+
+#include "cperf.h"
+#include "cperf_options.h"
+#include "cperf_test_vectors.h"
+
+
+typedef struct rte_cryptodev_sym_session *(*cperf_sessions_create_t)(
+ uint8_t dev_id, const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector);
+
+typedef int (*cperf_populate_ops_t)(struct rte_crypto_op **ops,
+ struct rte_mbuf **bufs, uint16_t nb_ops,
+ struct rte_cryptodev_sym_session *sess,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector);
+
+
+typedef int (*cperf_verify_crypto_op_t)(struct rte_mbuf *m,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector);
+
+struct cperf_op_fns {
+ cperf_sessions_create_t sess_create;
+ cperf_populate_ops_t populate_ops;
+ cperf_verify_crypto_op_t verify_op;
+};
+
+const struct cperf_op_fns *
+cperf_get_op_functions(const struct cperf_options *options);
+
+#endif /* _CPERF_OPS_ */
diff --git a/app/crypto-perf/cperf_options.h b/app/crypto-perf/cperf_options.h
new file mode 100644
index 0000000..28c8660
--- /dev/null
+++ b/app/crypto-perf/cperf_options.h
@@ -0,0 +1,95 @@
+
+#ifndef _CPERF_OPTIONS_
+#define _CPERF_OPTIONS_
+
+#include <rte_crypto.h>
+
+#define CPERF_PTEST_TYPE ("ptest")
+#define CPERF_SILENT ("silent")
+
+#define CPERF_POOL_SIZE ("pool-sz")
+#define CPERF_TOTAL_OPS ("total-ops")
+#define CPERF_BURST_SIZE ("burst-sz")
+#define CPERF_BUFFER_SIZE ("buffer-sz")
+#define CPERF_SEGMENTS_NB ("segments-nb")
+
+#define CPERF_DEVTYPE ("devtype")
+#define CPERF_OPTYPE ("optype")
+#define CPERF_SESSIONLESS ("sessionless")
+#define CPERF_VERIFY ("verify")
+
+#define CPERF_CIPHER_ALGO ("cipher-algo")
+#define CPERF_CIPHER_OP ("cipher-op")
+#define CPERF_CIPHER_KEY_SZ ("cipher-key-sz")
+#define CPERF_CIPHER_IV_SZ ("cipher-iv-sz")
+
+#define CPERF_AUTH_ALGO ("auth-algo")
+#define CPERF_AUTH_OP ("auth-op")
+#define CPERF_AUTH_KEY_SZ ("auth-key-sz")
+#define CPERF_AUTH_DIGEST_SZ ("auth-digest-sz")
+#define CPERF_AUTH_AAD_SZ ("auth-aad-sz")
+
+
+enum cperf_perf_test_type {
+ CPERF_TEST_TYPE_THROUGHPUT,
+ CPERF_TEST_TYPE_CYCLECOUNT,
+ CPERF_TEST_TYPE_LATENCY
+};
+
+
+extern const char *cperf_test_type_strs[];
+
+enum cperf_op_type {
+ CPERF_CIPHER_ONLY = 1,
+ CPERF_AUTH_ONLY,
+ CPERF_CIPHER_THEN_AUTH,
+ CPERF_AUTH_THEN_CIPHER,
+ CPERF_AEAD
+};
+
+extern const char *cperf_op_type_strs[];
+
+struct cperf_options {
+ enum cperf_perf_test_type test;
+
+ uint32_t pool_sz;
+ uint32_t total_ops;
+ uint32_t burst_sz;
+ uint32_t buffer_sz;
+ uint32_t segments_nb;
+
+ char device_type[RTE_CRYPTODEV_NAME_LEN];
+ enum cperf_op_type op_type;
+
+ uint32_t sessionless:1;
+ uint32_t verify:1;
+ uint32_t silent:1;
+
+ enum rte_crypto_cipher_algorithm cipher_algo;
+ enum rte_crypto_cipher_operation cipher_op;
+
+ uint32_t cipher_key_sz;
+ uint32_t cipher_iv_sz;
+
+ enum rte_crypto_auth_algorithm auth_algo;
+ enum rte_crypto_auth_operation auth_op;
+
+ uint32_t auth_key_sz;
+ uint32_t auth_digest_sz;
+ uint32_t auth_aad_sz;
+};
+
+void
+cperf_options_default(struct cperf_options *options);
+
+int
+cperf_options_parse(struct cperf_options *options,
+ int argc, char **argv);
+
+int
+cperf_options_check(struct cperf_options *options);
+
+void
+cperf_options_dump(struct cperf_options *options);
+
+#endif
diff --git a/app/crypto-perf/cperf_options_parsing.c b/app/crypto-perf/cperf_options_parsing.c
new file mode 100644
index 0000000..f09e91b
--- /dev/null
+++ b/app/crypto-perf/cperf_options_parsing.c
@@ -0,0 +1,695 @@
+/*-
+ * 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 <getopt.h>
+
+#include "cperf_options.h"
+
+
+
+struct name_id_map {
+ const char *name;
+ uint32_t id;
+};
+
+static int
+get_str_key_id_mapping(struct name_id_map *map, unsigned int map_len,
+ const char *str_key)
+{
+ unsigned int i;
+
+ for (i = 0; i < map_len; i++) {
+
+ if (strcmp(str_key, map[i].name) == 0)
+ return map[i].id;
+ }
+
+ return -1;
+}
+
+static int
+parse_cperf_test_type(struct cperf_options *opts, const char *arg) {
+ struct name_id_map cperftest_namemap[] = {
+ {
+ cperf_test_type_strs[CPERF_TEST_TYPE_THROUGHPUT],
+ CPERF_TEST_TYPE_THROUGHPUT
+ },
+ {
+ cperf_test_type_strs[CPERF_TEST_TYPE_CYCLECOUNT],
+ CPERF_TEST_TYPE_CYCLECOUNT
+ },
+ {
+ cperf_test_type_strs[CPERF_TEST_TYPE_LATENCY],
+ CPERF_TEST_TYPE_LATENCY
+ }
+ };
+
+ int id = get_str_key_id_mapping(
+ (struct name_id_map *)cperftest_namemap,
+ RTE_DIM(cperftest_namemap), arg);
+ if (id < 0) {
+ RTE_LOG(ERR, USER1, "failed to parse test type");
+ return -1;
+ }
+
+ opts->test = (enum cperf_perf_test_type)id;
+
+ return 0;
+}
+
+static int
+parse_uint32_t(uint32_t *value, const char *arg)
+{
+ char *end = NULL;
+ unsigned long n = strtoul(arg, &end, 10);
+
+ if ((optarg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+
+ *value = n;
+
+ return 0;
+}
+
+static int
+parse_total_ops(struct cperf_options *opts, const char *arg) {
+ int ret = parse_uint32_t(&opts->total_ops, arg);
+
+ if (ret)
+ RTE_LOG(ERR, USER1, "failed to parse total operations count");
+
+ return ret;
+}
+
+static int
+parse_pool_sz(struct cperf_options *opts, const char *arg) {
+ int ret = parse_uint32_t(&opts->pool_sz, arg);
+
+ if (ret)
+ RTE_LOG(ERR, USER1, "failed to parse pool size");
+ return ret;
+}
+
+static int
+parse_burst_sz(struct cperf_options *opts, const char *arg) {
+ int ret = parse_uint32_t(&opts->burst_sz, arg);
+
+ if (ret)
+ RTE_LOG(ERR, USER1, "failed to parse burst size");
+ return ret;
+}
+
+static int
+parse_buffer_sz(struct cperf_options *opts, const char *arg)
+{
+ uint32_t i, valid_buf_sz[] = {
+ 32, 64, 128, 256, 384, 512, 768, 1024, 1280, 1536, 1792,
+ 2048
+ };
+
+ if (parse_uint32_t(&opts->buffer_sz, arg)) {
+ RTE_LOG(ERR, USER1, "failed to parse buffer size");
+ return -1;
+ }
+
+ for (i = 0; i < RTE_DIM(valid_buf_sz); i++)
+ if (valid_buf_sz[i] == opts->buffer_sz)
+ return 0;
+
+ RTE_LOG(ERR, USER1, "invalid buffer size specified");
+ return -1;
+}
+
+static int
+parse_segments_nb(struct cperf_options *opts, const char *arg)
+{
+ int ret = parse_uint32_t(&opts->segments_nb, arg);
+
+ if (ret) {
+ RTE_LOG(ERR, USER1, "failed to parse segments number\n");
+ return -1;
+ }
+
+ if ((opts->segments_nb == 0) || (opts->segments_nb > 255)) {
+ RTE_LOG(ERR, USER1, "invalid segments number specified\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+parse_device_type(struct cperf_options *opts, const char *arg)
+{
+ if (strlen(arg) > (sizeof(opts->device_type) - 1))
+ return -1;
+
+ strncpy(opts->device_type, arg, sizeof(opts->device_type));
+
+ return 0;
+}
+
+static int
+parse_op_type(struct cperf_options *opts, const char *arg) {
+ struct name_id_map optype_namemap[] = {
+ {
+ cperf_op_type_strs[CPERF_CIPHER_ONLY],
+ CPERF_CIPHER_ONLY
+ },
+ {
+ cperf_op_type_strs[CPERF_AUTH_ONLY],
+ CPERF_AUTH_ONLY
+ },
+ {
+ cperf_op_type_strs[CPERF_CIPHER_THEN_AUTH],
+ CPERF_CIPHER_THEN_AUTH
+ },
+ {
+ cperf_op_type_strs[CPERF_AUTH_THEN_CIPHER],
+ CPERF_AUTH_THEN_CIPHER
+ },
+ {
+ cperf_op_type_strs[CPERF_AEAD],
+ CPERF_AEAD
+ }
+ };
+
+ int id = get_str_key_id_mapping(optype_namemap,
+ RTE_DIM(optype_namemap), arg);
+ if (id < 0) {
+ RTE_LOG(ERR, USER1, "invalid opt type specified");
+ return -1;
+ }
+
+ opts->op_type = (enum cperf_op_type)id;
+
+ return 0;
+}
+
+static int
+parse_sessionless(struct cperf_options *opts,
+ const char *arg __rte_unused) {
+ opts->sessionless = 1;
+ return 0;
+}
+
+static int
+parse_verify(struct cperf_options *opts,
+ const char *arg __rte_unused) {
+ opts->verify = 1;
+ return 0;
+}
+
+static int
+parse_silent(struct cperf_options *opts,
+ const char *arg __rte_unused) {
+ opts->silent = 1;
+ return 0;
+}
+
+
+static int
+parse_cipher_algo(struct cperf_options *opts, const char *arg) {
+ struct name_id_map cipher_algo_namemap[] = {
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_3DES_CBC],
+ RTE_CRYPTO_CIPHER_3DES_CBC
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_3DES_ECB],
+ RTE_CRYPTO_CIPHER_3DES_ECB
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_3DES_CTR],
+ RTE_CRYPTO_CIPHER_3DES_CTR
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_AES_CBC],
+ RTE_CRYPTO_CIPHER_AES_CBC
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_AES_CCM],
+ RTE_CRYPTO_CIPHER_AES_CCM
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_AES_CTR],
+ RTE_CRYPTO_CIPHER_AES_CTR
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_AES_ECB],
+ RTE_CRYPTO_CIPHER_AES_ECB
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_AES_GCM],
+ RTE_CRYPTO_CIPHER_AES_GCM
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_AES_F8],
+ RTE_CRYPTO_CIPHER_AES_F8
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_AES_XTS],
+ RTE_CRYPTO_CIPHER_AES_XTS
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_ARC4],
+ RTE_CRYPTO_CIPHER_ARC4
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_NULL],
+ RTE_CRYPTO_CIPHER_NULL
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_KASUMI_F8],
+ RTE_CRYPTO_CIPHER_KASUMI_F8
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_SNOW3G_UEA2],
+ RTE_CRYPTO_CIPHER_SNOW3G_UEA2
+ },
+ {
+ rte_crypto_cipher_algorithm_strings[RTE_CRYPTO_CIPHER_ZUC_EEA3],
+ RTE_CRYPTO_CIPHER_ZUC_EEA3
+ },
+ };
+
+
+ int id = get_str_key_id_mapping(cipher_algo_namemap,
+ RTE_DIM(cipher_algo_namemap), arg);
+ if (id < 0) {
+ RTE_LOG(ERR, USER1, "Invalid cipher algorithm specified/n");
+ return -1;
+ }
+
+ opts->cipher_algo = (enum rte_crypto_cipher_algorithm)id;
+
+ return 0;
+}
+
+static int
+parse_cipher_op(struct cperf_options *opts, const char *arg)
+{
+ struct name_id_map cipher_op_namemap[] = {
+ {
+ rte_crypto_cipher_operation_strings[RTE_CRYPTO_CIPHER_OP_ENCRYPT],
+ RTE_CRYPTO_CIPHER_OP_ENCRYPT },
+ {
+ rte_crypto_cipher_operation_strings[RTE_CRYPTO_CIPHER_OP_DECRYPT],
+ RTE_CRYPTO_CIPHER_OP_DECRYPT
+ }
+ };
+
+ int id = get_str_key_id_mapping(cipher_op_namemap,
+ RTE_DIM(cipher_op_namemap), arg);
+ if (id < 0) {
+ RTE_LOG(ERR, USER1, "Invalid cipher operation specified/n");
+ return -1;
+ }
+
+ opts->cipher_op = (enum rte_crypto_cipher_operation)id;
+
+ return 0;
+}
+
+static int
+parse_cipher_key_sz(struct cperf_options *opts, const char *arg)
+{
+ return parse_uint32_t(&opts->cipher_key_sz, arg);
+}
+
+static int
+parse_cipher_iv_sz(struct cperf_options *opts, const char *arg)
+{
+ return parse_uint32_t(&opts->cipher_iv_sz, arg);
+}
+
+static int
+parse_auth_algo(struct cperf_options *opts, const char *arg) {
+ struct name_id_map cipher_auth_namemap[] = {
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_AES_CBC_MAC],
+ RTE_CRYPTO_AUTH_AES_CBC_MAC
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_AES_CCM],
+ RTE_CRYPTO_AUTH_AES_CCM
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_AES_CMAC],
+ RTE_CRYPTO_AUTH_AES_CMAC
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_AES_GCM],
+ RTE_CRYPTO_AUTH_AES_GCM
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_AES_GMAC],
+ RTE_CRYPTO_AUTH_AES_GMAC
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_AES_XCBC_MAC],
+ RTE_CRYPTO_AUTH_AES_XCBC_MAC
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_MD5],
+ RTE_CRYPTO_AUTH_MD5
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_MD5_HMAC],
+ RTE_CRYPTO_AUTH_MD5_HMAC
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_SHA1],
+ RTE_CRYPTO_AUTH_SHA1
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_SHA1_HMAC],
+ RTE_CRYPTO_AUTH_SHA1_HMAC
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_SHA224],
+ RTE_CRYPTO_AUTH_SHA224
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_SHA224_HMAC],
+ RTE_CRYPTO_AUTH_SHA224_HMAC
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_SHA256],
+ RTE_CRYPTO_AUTH_SHA256
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_SHA256_HMAC],
+ RTE_CRYPTO_AUTH_SHA256_HMAC
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_SHA384],
+ RTE_CRYPTO_AUTH_SHA384
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_SHA384_HMAC],
+ RTE_CRYPTO_AUTH_SHA384_HMAC
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_SHA512],
+ RTE_CRYPTO_AUTH_SHA512
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_SHA512_HMAC],
+ RTE_CRYPTO_AUTH_SHA512_HMAC
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_KASUMI_F9],
+ RTE_CRYPTO_AUTH_KASUMI_F9
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_SNOW3G_UIA2],
+ RTE_CRYPTO_AUTH_SNOW3G_UIA2
+ },
+ {
+ rte_crypto_auth_algorithm_strings[RTE_CRYPTO_AUTH_ZUC_EIA3],
+ RTE_CRYPTO_AUTH_ZUC_EIA3
+ },
+ };
+
+
+ int id = get_str_key_id_mapping(cipher_auth_namemap,
+ RTE_DIM(cipher_auth_namemap), arg);
+ if (id < 0) {
+ RTE_LOG(ERR, USER1, "invalid authentication algorithm specified"
+ "\n");
+ return -1;
+ }
+
+ opts->auth_algo = (enum rte_crypto_auth_algorithm)id;
+
+ return 0;
+}
+
+static int
+parse_auth_op(struct cperf_options *opts, const char *arg)
+{
+ struct name_id_map auth_op_namemap[] = {
+ {
+ rte_crypto_auth_operation_strings[RTE_CRYPTO_AUTH_OP_GENERATE],
+ RTE_CRYPTO_AUTH_OP_GENERATE },
+ {
+ rte_crypto_auth_operation_strings[RTE_CRYPTO_AUTH_OP_VERIFY],
+ RTE_CRYPTO_AUTH_OP_VERIFY
+ }
+ };
+
+ int id = get_str_key_id_mapping(auth_op_namemap,
+ RTE_DIM(auth_op_namemap), arg);
+ if (id < 0) {
+ RTE_LOG(ERR, USER1, "invalid authentication operation specified"
+ "\n");
+ return -1;
+ }
+
+ opts->auth_op = (enum rte_crypto_auth_operation)id;
+
+ return 0;
+}
+
+static int
+parse_auth_key_sz(struct cperf_options *opts, const char *arg)
+{
+ return parse_uint32_t(&opts->auth_key_sz, arg);
+}
+
+static int
+parse_auth_digest_sz(struct cperf_options *opts, const char *arg)
+{
+ return parse_uint32_t(&opts->auth_digest_sz, arg);
+}
+
+static int
+parse_auth_aad_sz(struct cperf_options *opts, const char *arg)
+{
+ return parse_uint32_t(&opts->auth_aad_sz, arg);
+}
+
+typedef int (*option_parser_t)(struct cperf_options *opts,
+ const char *arg);
+
+struct long_opt_parser {
+ const char *lgopt_name;
+ option_parser_t parser_fn;
+
+};
+
+static struct option lgopts[] = {
+
+ { CPERF_PTEST_TYPE, required_argument, 0, 0 },
+
+ { CPERF_POOL_SIZE, required_argument, 0, 0 },
+ { CPERF_TOTAL_OPS, required_argument, 0, 0 },
+ { CPERF_BURST_SIZE, required_argument, 0, 0 },
+ { CPERF_BUFFER_SIZE, required_argument, 0, 0 },
+ { CPERF_SEGMENTS_NB, required_argument, 0, 0 },
+
+ { CPERF_DEVTYPE, required_argument, 0, 0 },
+ { CPERF_OPTYPE, required_argument, 0, 0 },
+
+ { CPERF_SILENT, no_argument, 0, 0 },
+ { CPERF_SESSIONLESS, no_argument, 0, 0 },
+ { CPERF_VERIFY, no_argument, 0, 0 },
+
+ { CPERF_CIPHER_ALGO, required_argument, 0, 0 },
+ { CPERF_CIPHER_OP, required_argument, 0, 0 },
+
+ { CPERF_CIPHER_KEY_SZ, required_argument, 0, 0 },
+ { CPERF_CIPHER_IV_SZ, required_argument, 0, 0 },
+
+ { CPERF_AUTH_ALGO, required_argument, 0, 0 },
+ { CPERF_AUTH_OP, required_argument, 0, 0 },
+
+ { CPERF_AUTH_KEY_SZ, required_argument, 0, 0 },
+ { CPERF_AUTH_DIGEST_SZ, required_argument, 0, 0 },
+ { CPERF_AUTH_AAD_SZ, required_argument, 0, 0 },
+
+ { NULL, 0, 0, 0 }
+};
+
+void
+cperf_options_default(struct cperf_options *opts)
+{
+ opts->test = CPERF_TEST_TYPE_THROUGHPUT;
+
+ opts->pool_sz = 100000;
+ opts->total_ops = 10000000;
+ opts->burst_sz = 32;
+ opts->buffer_sz = 64;
+ opts->segments_nb = 1;
+
+ strncpy(opts->device_type, "crypto_aesni_mb",
+ sizeof(opts->device_type));
+
+ opts->op_type = CPERF_CIPHER_THEN_AUTH;
+
+ opts->silent = 0;
+ opts->verify = 0;
+ opts->sessionless = 0;
+
+ opts->cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC;
+ opts->cipher_op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
+ opts->cipher_key_sz = 16;
+ opts->cipher_iv_sz = 16;
+
+ opts->auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC;
+ opts->auth_op = RTE_CRYPTO_AUTH_OP_GENERATE;
+
+ opts->auth_key_sz = 64;
+ opts->auth_digest_sz = 12;
+ opts->auth_aad_sz = 0;
+}
+
+static int
+cperf_opts_parse_long(int opt_idx, struct cperf_options *opts)
+{
+ struct long_opt_parser parsermap[] = {
+ { CPERF_PTEST_TYPE, parse_cperf_test_type },
+ { CPERF_SILENT, parse_silent },
+ { CPERF_POOL_SIZE, parse_pool_sz },
+ { CPERF_TOTAL_OPS, parse_total_ops },
+ { CPERF_BURST_SIZE, parse_burst_sz },
+ { CPERF_BUFFER_SIZE, parse_buffer_sz },
+ { CPERF_SEGMENTS_NB, parse_segments_nb },
+ { CPERF_DEVTYPE, parse_device_type },
+ { CPERF_OPTYPE, parse_op_type },
+ { CPERF_SESSIONLESS, parse_sessionless },
+ { CPERF_VERIFY, parse_verify },
+ { CPERF_CIPHER_ALGO, parse_cipher_algo },
+ { CPERF_CIPHER_OP, parse_cipher_op },
+ { CPERF_CIPHER_KEY_SZ, parse_cipher_key_sz },
+ { CPERF_CIPHER_IV_SZ, parse_cipher_iv_sz },
+ { CPERF_AUTH_ALGO, parse_auth_algo },
+ { CPERF_AUTH_OP, parse_auth_op },
+ { CPERF_AUTH_KEY_SZ, parse_auth_key_sz },
+ { CPERF_AUTH_DIGEST_SZ, parse_auth_digest_sz },
+ { CPERF_AUTH_AAD_SZ, parse_auth_aad_sz },
+ };
+ unsigned int i;
+
+ for (i = 0; i < RTE_DIM(parsermap); i++) {
+ if (strncmp(lgopts[opt_idx].name, parsermap[i].lgopt_name,
+ strlen(parsermap[i].lgopt_name)) == 0)
+ return parsermap[i].parser_fn(opts, optarg);
+ }
+
+ return -EINVAL;
+}
+
+int
+cperf_options_parse(struct cperf_options *options, int argc, char **argv)
+{
+ int opt, retval, opt_idx;
+
+ while ((opt = getopt_long(argc, argv, "", lgopts, &opt_idx)) != EOF) {
+ switch (opt) {
+ /* long options */
+ case 0:
+
+ retval = cperf_opts_parse_long(opt_idx, options);
+ if (retval != 0)
+ return retval;
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int
+cperf_options_check(struct cperf_options *options)
+{
+ if (options->segments_nb > options->buffer_sz) {
+ RTE_LOG(ERR, USER1,
+ "Segments number greater than buffer size.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void
+cperf_options_dump(struct cperf_options *opts)
+{
+ printf("# Crypto Performance Application Options:\n");
+ printf("#\n");
+ printf("# cperf test: %s\n", cperf_test_type_strs[opts->test]);
+ printf("#\n");
+ printf("# size of crypto op / mbuf pool: %u\n", opts->pool_sz);
+ printf("# total number of ops: %u\n", opts->total_ops);
+ printf("# burst size: %u\n", opts->burst_sz);
+ printf("# buffer size: %u\n", opts->buffer_sz);
+ printf("# segments per buffer: %u\n", opts->segments_nb);
+ printf("#\n");
+ printf("# cryptodev type: %s\n", opts->device_type);
+ printf("#\n");
+ printf("# crypto operation: %s\n", cperf_op_type_strs[opts->op_type]);
+ printf("# verify operation: %s\n", opts->verify ? "yes" : "no");
+ printf("# sessionless: %s\n", opts->sessionless ? "yes" : "no");
+ printf("#\n");
+
+ if (opts->op_type == CPERF_AUTH_ONLY ||
+ opts->op_type == CPERF_CIPHER_THEN_AUTH ||
+ opts->op_type == CPERF_AUTH_THEN_CIPHER ||
+ opts->op_type == CPERF_AEAD) {
+ printf("# auth algorithm: %s\n",
+ rte_crypto_auth_algorithm_strings[opts->auth_algo]);
+ printf("# auth operation: %s\n",
+ rte_crypto_auth_operation_strings[opts->auth_op]);
+ printf("# auth key size: %u\n", opts->auth_key_sz);
+ printf("# auth digest size: %u\n", opts->auth_digest_sz);
+ printf("# auth aad size: %u\n", opts->auth_aad_sz);
+ printf("#\n");
+ }
+
+ if (opts->op_type == CPERF_CIPHER_ONLY ||
+ opts->op_type == CPERF_CIPHER_THEN_AUTH ||
+ opts->op_type == CPERF_AUTH_THEN_CIPHER ||
+ opts->op_type == CPERF_AEAD) {
+ printf("# cipher algorithm: %s\n",
+ rte_crypto_cipher_algorithm_strings[opts->cipher_algo]);
+ printf("# cipher operation: %s\n",
+ rte_crypto_cipher_operation_strings[opts->cipher_op]);
+ printf("# cipher key size: %u\n", opts->cipher_key_sz);
+ printf("# cipher iv size: %u\n", opts->cipher_iv_sz);
+ printf("#\n");
+ }
+}
diff --git a/app/crypto-perf/cperf_test_cyclecount.c b/app/crypto-perf/cperf_test_cyclecount.c
new file mode 100644
index 0000000..e69de29
diff --git a/app/crypto-perf/cperf_test_latency.c b/app/crypto-perf/cperf_test_latency.c
new file mode 100644
index 0000000..870a35a
--- /dev/null
+++ b/app/crypto-perf/cperf_test_latency.c
@@ -0,0 +1,455 @@
+/*-
+ * 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_malloc.h>
+#include <rte_cycles.h>
+#include <rte_crypto.h>
+#include <rte_cryptodev.h>
+
+#include "cperf_test_latency.h"
+#include "cperf_ops.h"
+
+struct cperf_latency_results {
+
+ uint64_t ops_failed;
+
+ uint64_t enqd_tot;
+ uint64_t enqd_max;
+ uint64_t enqd_min;
+
+ uint64_t deqd_tot;
+ uint64_t deqd_max;
+ uint64_t deqd_min;
+
+ uint64_t cycles_tot;
+ uint64_t cycles_max;
+ uint64_t cycles_min;
+
+ uint64_t num;
+};
+
+struct cperf_latency_ctx {
+ uint8_t dev_id;
+ uint16_t qp_id;
+ uint8_t lcore_id;
+
+ struct rte_mempool *pkt_mbuf_pool;
+ struct rte_mbuf **mbufs;
+
+ struct rte_mempool *crypto_op_pool;
+
+ struct rte_cryptodev_sym_session *sess;
+
+ cperf_populate_ops_t populate_ops;
+ cperf_verify_crypto_op_t verify_op_output;
+
+ const struct cperf_options *options;
+ const struct cperf_test_vector *test_vector;
+ struct cperf_latency_results results;
+};
+
+#define max(a, b) (a > b ? (uint64_t)a : (uint64_t)b)
+#define min(a, b) (a < b ? (uint64_t)a : (uint64_t)b)
+
+static void
+cperf_latency_test_free(struct cperf_latency_ctx *ctx, uint32_t mbuf_nb)
+{
+ uint32_t i;
+
+ if (ctx) {
+ if (ctx->sess)
+ rte_cryptodev_sym_session_free(ctx->dev_id, ctx->sess);
+
+ if (ctx->mbufs) {
+ for (i = 0; i < mbuf_nb; i++)
+ rte_pktmbuf_free(ctx->mbufs[i]);
+
+ rte_free(ctx->mbufs);
+ }
+
+ if (ctx->pkt_mbuf_pool)
+ rte_mempool_free(ctx->pkt_mbuf_pool);
+
+ if (ctx->crypto_op_pool)
+ rte_mempool_free(ctx->crypto_op_pool);
+
+ rte_free(ctx);
+ }
+}
+
+static struct rte_mbuf *
+cperf_mbuf_create(struct rte_mempool *mempool,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector)
+{
+ struct rte_mbuf *mbuf;
+ uint32_t segment_sz = options->buffer_sz / options->segments_nb;
+ uint32_t last_sz = options->buffer_sz % options->segments_nb;
+ uint32_t segments_nb = options->segments_nb;
+ uint8_t *mbuf_data;
+ uint8_t *test_data =
+ (options->cipher_op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+ test_vector->plaintext.data :
+ test_vector->ciphertext.data;
+
+ mbuf = rte_pktmbuf_alloc(mempool);
+ if (mbuf == NULL)
+ goto error;
+
+ mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf, segment_sz);
+ if (mbuf_data == NULL)
+ goto error;
+
+ memcpy(mbuf_data, test_data, segment_sz);
+ test_data += segment_sz;
+ segments_nb--;
+
+ while (segments_nb) {
+ struct rte_mbuf *m;
+
+ m = rte_pktmbuf_alloc(mempool);
+ if (m == NULL)
+ goto error;
+
+ rte_pktmbuf_chain(mbuf, m);
+
+ mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf, segment_sz);
+ if (mbuf_data == NULL)
+ goto error;
+
+ memcpy(mbuf_data, test_data, segment_sz);
+ test_data += segment_sz;
+ segments_nb--;
+ }
+
+ if (last_sz) {
+ mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf, last_sz);
+ if (mbuf_data == NULL)
+ goto error;
+
+ memcpy(mbuf_data, test_data, last_sz);
+ }
+
+ mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf,
+ options->auth_digest_sz);
+ if (mbuf_data == NULL)
+ goto error;
+
+ if (options->op_type == CPERF_AEAD) {
+ uint8_t *aead = (uint8_t *)rte_pktmbuf_prepend(mbuf,
+ RTE_ALIGN_CEIL(options->auth_aad_sz, 16));
+
+ if (aead == NULL)
+ goto error;
+
+ memcpy(aead, test_vector->aad.data, test_vector->aad.length);
+ }
+
+ return mbuf;
+error:
+ if (mbuf != NULL)
+ rte_pktmbuf_free(mbuf);
+
+ return NULL;
+}
+
+void *
+cperf_latency_test_constructor(uint8_t dev_id, uint16_t qp_id,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector,
+ const struct cperf_op_fns *op_fns)
+{
+ struct cperf_latency_ctx *ctx = NULL;
+ unsigned int mbuf_idx;
+ char pool_name[32] = "";
+
+ ctx = rte_malloc(NULL, sizeof(struct cperf_latency_ctx), 0);
+ if (ctx == NULL)
+ goto err;
+
+ ctx->dev_id = dev_id;
+ ctx->qp_id = qp_id;
+
+ ctx->populate_ops = op_fns->populate_ops;
+ ctx->options = options;
+ ctx->test_vector = test_vector;
+
+ ctx->sess = op_fns->sess_create(dev_id, options, test_vector);
+ if (ctx->sess == NULL)
+ goto err;
+
+ snprintf(pool_name, sizeof(pool_name), "cperf_mbuf_pool_cdev_%d",
+ dev_id);
+
+ ctx->pkt_mbuf_pool = rte_pktmbuf_pool_create(pool_name,
+ options->pool_sz * options->segments_nb, 0, 0,
+ RTE_PKTMBUF_HEADROOM +
+ RTE_CACHE_LINE_ROUNDUP(
+ (options->buffer_sz / options->segments_nb) +
+ (options->buffer_sz % options->segments_nb) +
+ options->auth_digest_sz * 2),
+ rte_socket_id());
+ if (ctx->pkt_mbuf_pool == NULL)
+ goto err;
+
+ /*
+ * If the verify option is selected then our *total_ops* must be less
+ * than or equal to the *pool_sz*
+ */
+ if (ctx->options->verify &&
+ ctx->options->total_ops > ctx->options->pool_sz)
+ goto err;
+
+ /* Generate mbufs with plaintext populated for test */
+ if (ctx->options->pool_sz % ctx->options->burst_sz)
+ goto err;
+
+ ctx->mbufs = rte_malloc(NULL,
+ (sizeof(struct rte_mbuf *) * ctx->options->pool_sz), 0);
+
+ for (mbuf_idx = 0; mbuf_idx < options->pool_sz; mbuf_idx++) {
+ ctx->mbufs[mbuf_idx] = cperf_mbuf_create(ctx->pkt_mbuf_pool,
+ options,
+ test_vector);
+ if (ctx->mbufs[mbuf_idx] == NULL)
+ goto err;
+ }
+
+ snprintf(pool_name, sizeof(pool_name), "cperf_op_pool_cdev_%d",
+ dev_id);
+
+ ctx->crypto_op_pool = rte_crypto_op_pool_create(pool_name,
+ RTE_CRYPTO_OP_TYPE_SYMMETRIC, options->pool_sz, 0, 0,
+ rte_socket_id());
+ if (ctx->crypto_op_pool == NULL)
+ goto err;
+
+ return ctx;
+err:
+ cperf_latency_test_free(ctx, mbuf_idx);
+
+ return NULL;
+}
+
+int
+cperf_latency_test_runner(void *arg)
+{
+ struct cperf_latency_ctx *ctx = arg;
+
+ if (ctx == NULL)
+ return 0;
+
+ struct rte_crypto_op *ops[ctx->options->burst_sz];
+ struct rte_crypto_op *ops_processed[ctx->options->burst_sz];
+ uint64_t ops_enqd = 0, ops_deqd = 0;
+ uint16_t ops_unused = 0;
+ uint64_t m_idx = 0, i;
+
+ uint64_t tsc_val, tsc_end, tsc_start;
+ uint64_t tsc_max = 0, tsc_min = ~0UL, tsc_tot = 0, tsc_idx = 0;
+ uint64_t enqd_max = 0, enqd_min = ~0UL, enqd_tot = 0;
+ uint64_t deqd_max = 0, deqd_min = ~0UL, deqd_tot = 0;
+
+ uint32_t lcore = rte_lcore_id();
+
+ ctx->lcore_id = lcore;
+
+ printf("\n# Running latency test on device: %u, lcore: %u\n",
+ ctx->dev_id, lcore);
+
+ while (enqd_tot < ctx->options->total_ops) {
+
+ uint16_t burst_size = ((enqd_tot + ctx->options->burst_sz)
+ <= ctx->options->total_ops) ?
+ ctx->options->burst_sz :
+ ctx->options->total_ops -
+ enqd_tot;
+ uint16_t ops_needed = burst_size - ops_unused;
+ uint16_t op_offset = ctx->options->burst_sz - burst_size;
+
+ /* Allocate crypto ops from pool */
+ if (ops_needed != rte_crypto_op_bulk_alloc(
+ ctx->crypto_op_pool,
+ RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+ ops + op_offset, ops_needed))
+ return -1;
+
+ /* Setup crypto op, attach mbuf etc */
+ (ctx->populate_ops)(ops + op_offset, &ctx->mbufs[m_idx],
+ ops_needed, ctx->sess, ctx->options,
+ ctx->test_vector);
+
+ tsc_start = rte_rdtsc_precise();
+
+ /* Enqueue burst of ops on crypto device */
+ ops_enqd = rte_cryptodev_enqueue_burst(ctx->dev_id, ctx->qp_id,
+ ops + op_offset, burst_size);
+
+ /* Dequeue processed burst of ops from crypto device */
+ ops_deqd = rte_cryptodev_dequeue_burst(ctx->dev_id, ctx->qp_id,
+ ops_processed, ctx->options->burst_sz);
+
+ tsc_end = rte_rdtsc_precise();
+ tsc_val = (tsc_end - tsc_start);
+ tsc_max = max(tsc_val, tsc_max);
+ tsc_min = min(tsc_val, tsc_min);
+ tsc_tot += tsc_val;
+ tsc_idx++;
+
+ /*
+ * Calculate number of ops not enqueued (mainly for hw
+ * accelerators whose ingress queue can fill up).
+ */
+ ops_unused = burst_size - ops_enqd;
+
+ if (likely(ops_deqd)) {
+ /*
+ * free crypto ops so they can be reused. We don't free
+ * the mbufs here as we don't want to reuse them as
+ * the crypto operation will change the data and cause
+ * failures.
+ */
+ for (i = 0; i < ops_deqd; i++)
+ rte_crypto_op_free(ops_processed[i]);
+
+ deqd_tot += ops_deqd;
+ deqd_max = max(ops_deqd, deqd_max);
+ deqd_min = min(ops_deqd, deqd_min);
+ }
+
+ enqd_tot += ops_enqd;
+ enqd_max = max(ops_enqd, enqd_max);
+ enqd_min = min(ops_enqd, enqd_min);
+
+ m_idx += ops_needed;
+ m_idx = m_idx + ctx->options->burst_sz > ctx->options->pool_sz ?
+ 0 : m_idx;
+ }
+
+ /* Dequeue any operations still in the crypto device */
+ while (deqd_tot < ctx->options->total_ops) {
+ /* Sending 0 length burst to flush sw crypto device */
+ rte_cryptodev_enqueue_burst(ctx->dev_id, ctx->qp_id, NULL, 0);
+
+ /* dequeue burst */
+ ops_deqd = rte_cryptodev_dequeue_burst(ctx->dev_id, ctx->qp_id,
+ ops_processed, ctx->options->burst_sz);
+ if (ops_deqd != 0) {
+ for (i = 0; i < ops_deqd; i++)
+ rte_crypto_op_free(ops_processed[i]);
+
+ deqd_tot += ops_deqd;
+ deqd_max = max(ops_deqd, deqd_max);
+ deqd_min = min(ops_deqd, deqd_min);
+ }
+ }
+
+ if (ctx->options->verify) {
+ for (i = 0; i < ctx->options->total_ops; i++) {
+ if ((ctx->verify_op_output)(ctx->mbufs[i],
+ ctx->options, ctx->test_vector))
+ ctx->results.ops_failed++;
+ }
+ }
+
+ ctx->results.enqd_tot = enqd_tot;
+ ctx->results.enqd_max = enqd_max;
+ ctx->results.enqd_min = enqd_min;
+
+ ctx->results.deqd_tot = deqd_tot;
+ ctx->results.deqd_max = deqd_max;
+ ctx->results.deqd_min = deqd_min;
+
+ ctx->results.cycles_tot = tsc_tot;
+ ctx->results.cycles_max = tsc_max;
+ ctx->results.cycles_min = tsc_min;
+
+ ctx->results.num = tsc_idx;
+
+ return 0;
+}
+
+void
+cperf_latency_test_destructor(void *arg)
+{
+ struct cperf_latency_ctx *ctx = arg;
+
+ if (ctx == NULL)
+ return;
+
+ uint64_t etot, eavg, emax, emin;
+ uint64_t dtot, davg, dmax, dmin;
+ uint64_t ctot, cavg, cmax, cmin;
+ double ttot, tavg, tmax, tmin;
+
+ const uint64_t tunit = 1000000; /* us */
+ const uint64_t tsc_hz = rte_get_tsc_hz();
+
+ etot = ctx->results.enqd_tot;
+ eavg = ctx->results.enqd_tot / ctx->results.num;
+ emax = ctx->results.enqd_max;
+ emin = ctx->results.enqd_min;
+
+ dtot = ctx->results.deqd_tot;
+ davg = ctx->results.deqd_tot / ctx->results.num;
+ dmax = ctx->results.deqd_max;
+ dmin = ctx->results.deqd_min;
+
+ ctot = ctx->results.cycles_tot;
+ cavg = ctx->results.cycles_tot / ctx->results.num;
+ cmax = ctx->results.cycles_max;
+ cmin = ctx->results.cycles_min;
+
+ ttot = tunit*(double)(ctot) / tsc_hz;
+ tavg = tunit*(double)(cavg) / tsc_hz;
+ tmax = tunit*(double)(cmax) / tsc_hz;
+ tmin = tunit*(double)(cmin) / tsc_hz;
+
+ printf("\n# Device %d on lcore %u", ctx->dev_id, ctx->lcore_id);
+ printf("\n# total operations: %u", ctx->options->total_ops);
+ printf("\n# verified failed: %lu", ctx->results.ops_failed);
+ printf("\n# burst number: %lu", ctx->results.num);
+ printf("\n");
+ printf("\n# \t Total\t Average\t Maximum\t "
+ "Minimum");
+ printf("\n# enqueued\t%12lu\t%10lu\t%10lu\t%10lu",
+ etot, eavg, emax, emin);
+ printf("\n# dequeued\t%12lu\t%10lu\t%10lu\t%10lu",
+ dtot, davg, dmax, dmin);
+ printf("\n# cycles\t%12lu\t%10lu\t%10lu\t%10lu",
+ ctot, cavg, cmax, cmin);
+ printf("\n# time [us]\t%12.0f\t%10.3f\t%10.3f\t%10.3f",
+ ttot, tavg, tmax, tmin);
+ printf("\n\n");
+
+ cperf_latency_test_free(ctx, ctx->options->pool_sz);
+}
diff --git a/app/crypto-perf/cperf_test_latency.h b/app/crypto-perf/cperf_test_latency.h
new file mode 100644
index 0000000..5e3eea8
--- /dev/null
+++ b/app/crypto-perf/cperf_test_latency.h
@@ -0,0 +1,57 @@
+/*-
+ * 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 _CPERF_LATENCY_
+#define _CPERF_LATENCY_
+
+#include <stdint.h>
+
+#include <rte_mbuf.h>
+
+#include "cperf.h"
+#include "cperf_ops.h"
+#include "cperf_options.h"
+#include "cperf_test_vectors.h"
+
+void *
+cperf_latency_test_constructor(uint8_t dev_id, uint16_t qp_id,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector,
+ const struct cperf_op_fns *ops_fn);
+
+int
+cperf_latency_test_runner(void *test_ctx);
+
+void
+cperf_latency_test_destructor(void *test_ctx);
+
+#endif /* _CPERF_LATENCY_ */
diff --git a/app/crypto-perf/cperf_test_throughput.c b/app/crypto-perf/cperf_test_throughput.c
new file mode 100644
index 0000000..c65cf9f
--- /dev/null
+++ b/app/crypto-perf/cperf_test_throughput.c
@@ -0,0 +1,433 @@
+/*-
+ * 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_malloc.h>
+#include <rte_cycles.h>
+#include <rte_crypto.h>
+#include <rte_cryptodev.h>
+
+#include "cperf_test_throughput.h"
+#include "cperf_ops.h"
+
+struct cperf_throughput_results {
+ uint64_t ops_enqueued;
+ uint64_t ops_dequeued;
+
+ uint64_t ops_enqueued_failed;
+ uint64_t ops_dequeued_failed;
+
+ uint64_t ops_failed;
+
+ double ops_per_second;
+ double throughput_gbps;
+ double cycles_per_byte;
+};
+
+struct cperf_throughput_ctx {
+ uint8_t dev_id;
+ uint16_t qp_id;
+ uint8_t lcore_id;
+
+ struct rte_mempool *pkt_mbuf_pool;
+ struct rte_mbuf **mbufs;
+
+ struct rte_mempool *crypto_op_pool;
+
+ struct rte_cryptodev_sym_session *sess;
+
+ cperf_populate_ops_t populate_ops;
+ cperf_verify_crypto_op_t verify_op_output;
+
+ const struct cperf_options *options;
+ const struct cperf_test_vector *test_vector;
+ struct cperf_throughput_results results;
+
+};
+
+static void
+cperf_throughput_test_free(struct cperf_throughput_ctx *ctx, uint32_t mbuf_nb)
+{
+ uint32_t i;
+
+ if (ctx) {
+ if (ctx->sess)
+ rte_cryptodev_sym_session_free(ctx->dev_id, ctx->sess);
+
+ if (ctx->mbufs) {
+ for (i = 0; i < mbuf_nb; i++)
+ rte_pktmbuf_free(ctx->mbufs[i]);
+
+ rte_free(ctx->mbufs);
+ }
+
+ if (ctx->pkt_mbuf_pool)
+ rte_mempool_free(ctx->pkt_mbuf_pool);
+
+ if (ctx->crypto_op_pool)
+ rte_mempool_free(ctx->crypto_op_pool);
+
+ rte_free(ctx);
+ }
+}
+
+static struct rte_mbuf *
+cperf_mbuf_create(struct rte_mempool *mempool,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector)
+{
+ struct rte_mbuf *mbuf;
+ uint32_t segment_sz = options->buffer_sz / options->segments_nb;
+ uint32_t last_sz = options->buffer_sz % options->segments_nb;
+ uint32_t segments_nb = options->segments_nb;
+ uint8_t *mbuf_data;
+ uint8_t *test_data =
+ (options->cipher_op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
+ test_vector->plaintext.data :
+ test_vector->ciphertext.data;
+
+ mbuf = rte_pktmbuf_alloc(mempool);
+ if (mbuf == NULL)
+ goto error;
+
+ mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf, segment_sz);
+ if (mbuf_data == NULL)
+ goto error;
+
+ memcpy(mbuf_data, test_data, segment_sz);
+ test_data += segment_sz;
+ segments_nb--;
+
+ while (segments_nb) {
+ struct rte_mbuf *m;
+
+ m = rte_pktmbuf_alloc(mempool);
+ if (m == NULL)
+ goto error;
+
+ rte_pktmbuf_chain(mbuf, m);
+
+ mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf, segment_sz);
+ if (mbuf_data == NULL)
+ goto error;
+
+ memcpy(mbuf_data, test_data, segment_sz);
+ test_data += segment_sz;
+ segments_nb--;
+ }
+
+ if (last_sz) {
+ mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf, last_sz);
+ if (mbuf_data == NULL)
+ goto error;
+
+ memcpy(mbuf_data, test_data, last_sz);
+ }
+
+ mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf,
+ options->auth_digest_sz);
+ if (mbuf_data == NULL)
+ goto error;
+
+ if (options->op_type == CPERF_AEAD) {
+ uint8_t *aead = (uint8_t *)rte_pktmbuf_prepend(mbuf,
+ RTE_ALIGN_CEIL(options->auth_aad_sz, 16));
+
+ if (aead == NULL)
+ goto error;
+
+ memcpy(aead, test_vector->aad.data, test_vector->aad.length);
+ }
+
+ return mbuf;
+error:
+ if (mbuf != NULL)
+ rte_pktmbuf_free(mbuf);
+
+ return NULL;
+}
+
+void *
+cperf_throughput_test_constructor(uint8_t dev_id, uint16_t qp_id,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector,
+ const struct cperf_op_fns *op_fns)
+{
+ struct cperf_throughput_ctx *ctx = NULL;
+ unsigned int mbuf_idx;
+ char pool_name[32] = "";
+
+ ctx = rte_malloc(NULL, sizeof(struct cperf_throughput_ctx), 0);
+ if (ctx == NULL)
+ goto err;
+
+ ctx->dev_id = dev_id;
+ ctx->qp_id = qp_id;
+
+ ctx->populate_ops = op_fns->populate_ops;
+ ctx->options = options;
+ ctx->test_vector = test_vector;
+
+ ctx->sess = op_fns->sess_create(dev_id, options, test_vector);
+ if (ctx->sess == NULL)
+ goto err;
+
+ snprintf(pool_name, sizeof(pool_name), "cperf_mbuf_pool_cdev_%d",
+ dev_id);
+
+ ctx->pkt_mbuf_pool = rte_pktmbuf_pool_create(pool_name,
+ options->pool_sz * options->segments_nb, 0, 0,
+ RTE_PKTMBUF_HEADROOM +
+ RTE_CACHE_LINE_ROUNDUP(
+ (options->buffer_sz / options->segments_nb) +
+ (options->buffer_sz % options->segments_nb) +
+ options->auth_digest_sz * 2),
+ rte_socket_id());
+ if (ctx->pkt_mbuf_pool == NULL)
+ goto err;
+
+ /**
+ * If the verify option is selected then our *total_ops* must be less
+ * than or equal to the *pool_sz*
+ */
+ if (ctx->options->verify &&
+ ctx->options->total_ops > ctx->options->pool_sz)
+ goto err;
+
+ /* Generate mbufs with plaintext populated for test */
+ if (ctx->options->pool_sz % ctx->options->burst_sz)
+ goto err;
+
+ ctx->mbufs = rte_malloc(NULL,
+ (sizeof(struct rte_mbuf *) * ctx->options->pool_sz), 0);
+
+ for (mbuf_idx = 0; mbuf_idx < options->pool_sz; mbuf_idx++) {
+ ctx->mbufs[mbuf_idx] = cperf_mbuf_create(ctx->pkt_mbuf_pool,
+ options,
+ test_vector);
+ if (ctx->mbufs[mbuf_idx] == NULL)
+ goto err;
+ }
+
+ snprintf(pool_name, sizeof(pool_name), "cperf_op_pool_cdev_%d",
+ dev_id);
+
+ ctx->crypto_op_pool = rte_crypto_op_pool_create(pool_name,
+ RTE_CRYPTO_OP_TYPE_SYMMETRIC, options->pool_sz, 0, 0,
+ rte_socket_id());
+ if (ctx->crypto_op_pool == NULL)
+ goto err;
+
+ return ctx;
+err:
+ cperf_throughput_test_free(ctx, mbuf_idx);
+
+ return NULL;
+}
+
+
+int
+cperf_throughput_test_runner(void *test_ctx)
+{
+ struct cperf_throughput_ctx *ctx = test_ctx;
+
+ uint64_t ops_enqd = 0, ops_enqd_total = 0, ops_enqd_failed = 0;
+ uint64_t ops_deqd = 0, ops_deqd_total = 0, ops_deqd_failed = 0;
+
+ uint64_t i, m_idx = 0, tsc_start, tsc_end, tsc_duration;
+
+ uint16_t ops_unused = 0;
+
+ struct rte_crypto_op *ops[ctx->options->burst_sz];
+ struct rte_crypto_op *ops_processed[ctx->options->burst_sz];
+
+ uint32_t lcore = rte_lcore_id();
+
+ ctx->lcore_id = lcore;
+
+ printf("\n# Running throughput test on device: %u, lcore: %u\n",
+ ctx->dev_id, lcore);
+
+ rte_cryptodev_enqueue_burst(ctx->dev_id, ctx->qp_id, NULL, 0);
+
+ for (i = 0; i < ctx->options->total_ops; i++)
+ rte_cryptodev_dequeue_burst(ctx->dev_id, ctx->qp_id,
+ ops_processed, ctx->options->burst_sz);
+
+ tsc_start = rte_rdtsc_precise();
+
+ while (ops_enqd_total < ctx->options->total_ops) {
+
+ uint16_t burst_size = ((ops_enqd_total + ctx->options->burst_sz)
+ <= ctx->options->total_ops) ?
+ ctx->options->burst_sz :
+ ctx->options->total_ops -
+ ops_enqd_total;
+
+ uint16_t ops_needed = burst_size - ops_unused;
+ uint16_t op_offset = ctx->options->burst_sz - burst_size;
+
+ /* Allocate crypto ops from pool */
+ if (ops_needed != rte_crypto_op_bulk_alloc(
+ ctx->crypto_op_pool,
+ RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+ ops + op_offset, ops_needed))
+ return -1;
+
+ /* Setup crypto op, attach mbuf etc */
+ (ctx->populate_ops)(ops + op_offset, &ctx->mbufs[m_idx],
+ ops_needed, ctx->sess, ctx->options,
+ ctx->test_vector);
+
+ /* Enqueue burst of ops on crypto device */
+ ops_enqd = rte_cryptodev_enqueue_burst(ctx->dev_id, ctx->qp_id,
+ ops + op_offset, burst_size);
+ if (ops_enqd < burst_size)
+ ops_enqd_failed++;
+
+ /**
+ * Calculate number of ops not enqueued (mainly for hw
+ * accelerators whose ingress queue can fill up).
+ */
+ ops_unused = burst_size - ops_enqd;
+ ops_enqd_total += ops_enqd;
+
+
+ /* Dequeue processed burst of ops from crypto device */
+ ops_deqd = rte_cryptodev_dequeue_burst(ctx->dev_id, ctx->qp_id,
+ ops_processed, ctx->options->burst_sz);
+ if (likely(ops_deqd)) {
+ /* free crypto ops so they can be reused. We don't free
+ * the mbufs here as we don't want to reuse them as
+ * the crypto operation will change the data and cause
+ * failures.
+ */
+ for (i = 0; i < ops_deqd; i++)
+ rte_crypto_op_free(ops_processed[i]);
+
+ ops_deqd_total += ops_deqd;
+ } else {
+ /**
+ * Count dequeue polls which didn't return any
+ * processed operations. This statistic is mainly
+ * relevant to hw accelerators.
+ */
+ ops_deqd_failed++;
+ }
+
+ m_idx += ops_needed;
+ m_idx = m_idx + ctx->options->burst_sz > ctx->options->pool_sz ?
+ 0 : m_idx;
+ }
+
+ /* Dequeue any operations still in the crypto device */
+
+ while (ops_deqd_total < ctx->options->total_ops) {
+ /* Sending 0 length burst to flush sw crypto device */
+ rte_cryptodev_enqueue_burst(ctx->dev_id, ctx->qp_id, NULL, 0);
+
+ /* dequeue burst */
+ ops_deqd = rte_cryptodev_dequeue_burst(ctx->dev_id, ctx->qp_id,
+ ops_processed, ctx->options->burst_sz);
+ if (ops_deqd == 0)
+ ops_deqd_failed++;
+ else {
+ for (i = 0; i < ops_deqd; i++)
+ rte_crypto_op_free(ops_processed[i]);
+
+ ops_deqd_total += ops_deqd;
+ }
+ }
+
+ tsc_end = rte_rdtsc_precise();
+ tsc_duration = (tsc_end - tsc_start);
+
+
+ if (ctx->options->verify) {
+ int ret;
+
+ for (i = 0; i < ctx->options->total_ops; i++) {
+ ret = (ctx->verify_op_output)(ctx->mbufs[i],
+ ctx->options, ctx->test_vector);
+
+ if (ret)
+ ctx->results.ops_failed++;
+ }
+ }
+
+ /* Calculate average operations processed per second */
+ ctx->results.ops_per_second = ((double)ctx->options->total_ops /
+ tsc_duration) * rte_get_tsc_hz();
+
+ /* Calculate average throughput (Gbps) in bits per second */
+ ctx->results.throughput_gbps = ((ctx->results.ops_per_second *
+ ctx->options->buffer_sz * 8) / 1000000000);
+
+
+ /* Calculate average cycles per byte */
+ ctx->results.cycles_per_byte = ((double)tsc_duration /
+ ctx->options->total_ops) / ctx->options->buffer_sz;
+
+ ctx->results.ops_enqueued = ops_enqd_total;
+ ctx->results.ops_dequeued = ops_deqd_total;
+
+ ctx->results.ops_enqueued_failed = ops_enqd_failed;
+ ctx->results.ops_dequeued_failed = ops_deqd_failed;
+
+ return 0;
+}
+
+
+
+void
+cperf_throughput_test_destructor(void *arg)
+{
+ struct cperf_throughput_ctx *ctx = arg;
+ struct cperf_throughput_results *results = &ctx->results;
+
+ if (ctx == NULL)
+ return;
+
+ printf("\n# Device %d on lcore %u\n", ctx->dev_id, ctx->lcore_id);
+ printf("# Buffer Size(B)\t Enqueued\t Dequeued\tFailed Enq\tFailed "
+ "Deq\tOps(Millions)\tThroughput(Gbps)\tCycles Per Byte\n");
+ printf("\n%16u\t%10lu\t%10lu\t%10lu\t%10lu\t%13.0f\t%16.4f\t%15.2f\n",
+ ctx->options->buffer_sz,
+ results->ops_enqueued,
+ results->ops_dequeued,
+ results->ops_enqueued_failed,
+ results->ops_dequeued_failed,
+ results->ops_per_second,
+ results->throughput_gbps,
+ results->cycles_per_byte);
+
+ cperf_throughput_test_free(ctx, ctx->options->pool_sz);
+}
diff --git a/app/crypto-perf/cperf_test_throughput.h b/app/crypto-perf/cperf_test_throughput.h
new file mode 100644
index 0000000..497a490
--- /dev/null
+++ b/app/crypto-perf/cperf_test_throughput.h
@@ -0,0 +1,58 @@
+/*-
+ * 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 _CPERF_THROUGHPUT_
+#define _CPERF_THROUGHPUT_
+
+#include <stdint.h>
+
+#include <rte_mbuf.h>
+
+#include "cperf.h"
+#include "cperf_ops.h"
+#include "cperf_options.h"
+#include "cperf_test_vectors.h"
+
+
+void *
+cperf_throughput_test_constructor(uint8_t dev_id, uint16_t qp_id,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector,
+ const struct cperf_op_fns *ops_fn);
+
+int
+cperf_throughput_test_runner(void *test_ctx);
+
+void
+cperf_throughput_test_destructor(void *test_ctx);
+
+#endif /* _CPERF_THROUGHPUT_ */
diff --git a/app/crypto-perf/cperf_test_vectors.c b/app/crypto-perf/cperf_test_vectors.c
new file mode 100644
index 0000000..0ad0a61
--- /dev/null
+++ b/app/crypto-perf/cperf_test_vectors.c
@@ -0,0 +1,339 @@
+#include <rte_crypto.h>
+#include <rte_malloc.h>
+
+#include "cperf_test_vectors.h"
+
+uint8_t plaintext[2048] = {
+ 0x71, 0x75, 0x83, 0x98, 0x75, 0x42, 0x51, 0x09, 0x94, 0x02, 0x13, 0x20,
+ 0x15, 0x64, 0x46, 0x32, 0x08, 0x18, 0x91, 0x82, 0x86, 0x52, 0x23, 0x93,
+ 0x44, 0x54, 0x28, 0x68, 0x78, 0x78, 0x70, 0x06, 0x42, 0x74, 0x41, 0x27,
+ 0x73, 0x38, 0x53, 0x77, 0x51, 0x96, 0x53, 0x24, 0x03, 0x88, 0x74, 0x14,
+ 0x70, 0x23, 0x88, 0x30, 0x85, 0x18, 0x89, 0x27, 0x41, 0x71, 0x61, 0x23,
+ 0x04, 0x83, 0x30, 0x57, 0x26, 0x47, 0x23, 0x75, 0x25, 0x62, 0x53, 0x80,
+ 0x38, 0x34, 0x21, 0x33, 0x34, 0x51, 0x46, 0x29, 0x94, 0x64, 0x22, 0x67,
+ 0x25, 0x45, 0x70, 0x26, 0x74, 0x39, 0x46, 0x71, 0x08, 0x85, 0x27, 0x18,
+ 0x93, 0x39, 0x72, 0x11, 0x57, 0x26, 0x88, 0x46, 0x47, 0x49, 0x86, 0x92,
+ 0x03, 0x37, 0x96, 0x40, 0x84, 0x53, 0x67, 0x47, 0x60, 0x60, 0x37, 0x67,
+ 0x02, 0x68, 0x76, 0x62, 0x42, 0x01, 0x59, 0x11, 0x01, 0x89, 0x40, 0x87,
+ 0x58, 0x20, 0x51, 0x21, 0x66, 0x26, 0x26, 0x73, 0x03, 0x06, 0x14, 0x25,
+ 0x98, 0x42, 0x44, 0x67, 0x24, 0x78, 0x71, 0x45, 0x32, 0x61, 0x20, 0x26,
+ 0x08, 0x88, 0x44, 0x26, 0x40, 0x63, 0x76, 0x23, 0x78, 0x55, 0x81, 0x97,
+ 0x95, 0x89, 0x39, 0x07, 0x14, 0x50, 0x50, 0x73, 0x07, 0x20, 0x86, 0x83,
+ 0x74, 0x57, 0x72, 0x36, 0x68, 0x61, 0x14, 0x41, 0x56, 0x49, 0x64, 0x72,
+ 0x75, 0x81, 0x47, 0x91, 0x08, 0x76, 0x47, 0x06, 0x55, 0x77, 0x61, 0x45,
+ 0x50, 0x10, 0x07, 0x46, 0x46, 0x89, 0x80, 0x07, 0x24, 0x95, 0x39, 0x43,
+ 0x03, 0x75, 0x24, 0x35, 0x57, 0x82, 0x09, 0x64, 0x29, 0x24, 0x26, 0x66,
+ 0x67, 0x29, 0x05, 0x90, 0x82, 0x02, 0x45, 0x71, 0x21, 0x34, 0x25, 0x48,
+ 0x68, 0x26, 0x01, 0x18, 0x73, 0x18, 0x46, 0x15, 0x14, 0x33, 0x28, 0x44,
+ 0x24, 0x82, 0x20, 0x12, 0x99, 0x43, 0x68, 0x43, 0x25, 0x14, 0x34, 0x33,
+ 0x31, 0x13, 0x77, 0x44, 0x95, 0x22, 0x99, 0x02, 0x30, 0x50, 0x74, 0x43,
+ 0x81, 0x78, 0x32, 0x17, 0x09, 0x85, 0x04, 0x37, 0x31, 0x98, 0x76, 0x79,
+ 0x64, 0x10, 0x39, 0x89, 0x59, 0x90, 0x50, 0x15, 0x77, 0x39, 0x28, 0x14,
+ 0x30, 0x19, 0x68, 0x77, 0x89, 0x48, 0x86, 0x16, 0x11, 0x33, 0x84, 0x56,
+ 0x10, 0x20, 0x94, 0x72, 0x41, 0x69, 0x13, 0x00, 0x56, 0x27, 0x01, 0x57,
+ 0x46, 0x65, 0x65, 0x19, 0x33, 0x07, 0x62, 0x19, 0x91, 0x60, 0x29, 0x11,
+ 0x41, 0x25, 0x88, 0x21, 0x93, 0x85, 0x87, 0x40, 0x91, 0x25, 0x32, 0x86,
+ 0x76, 0x54, 0x92, 0x52, 0x72, 0x46, 0x61, 0x84, 0x20, 0x14, 0x65, 0x83,
+ 0x69, 0x90, 0x80, 0x11, 0x35, 0x70, 0x42, 0x64, 0x74, 0x85, 0x15, 0x23,
+ 0x06, 0x55, 0x67, 0x49, 0x76, 0x47, 0x11, 0x95, 0x00, 0x85, 0x05, 0x12,
+ 0x58, 0x53, 0x25, 0x73, 0x62, 0x81, 0x63, 0x82, 0x32, 0x75, 0x16, 0x48,
+ 0x04, 0x96, 0x75, 0x16, 0x43, 0x83, 0x41, 0x85, 0x95, 0x67, 0x27, 0x83,
+ 0x22, 0x43, 0x02, 0x27, 0x69, 0x62, 0x78, 0x50, 0x57, 0x66, 0x99, 0x89,
+ 0x05, 0x06, 0x35, 0x86, 0x37, 0x27, 0x48, 0x46, 0x50, 0x80, 0x96, 0x40,
+ 0x42, 0x36, 0x21, 0x54, 0x49, 0x18, 0x63, 0x38, 0x45, 0x76, 0x23, 0x20,
+ 0x28, 0x06, 0x17, 0x32, 0x58, 0x50, 0x49, 0x54, 0x29, 0x46, 0x18, 0x12,
+ 0x17, 0x50, 0x02, 0x80, 0x99, 0x53, 0x15, 0x02, 0x07, 0x14, 0x19, 0x60,
+ 0x56, 0x43, 0x76, 0x71, 0x49, 0x99, 0x54, 0x83, 0x28, 0x94, 0x30, 0x30,
+ 0x57, 0x05, 0x89, 0x80, 0x11, 0x03, 0x78, 0x35, 0x73, 0x52, 0x67, 0x39,
+ 0x67, 0x07, 0x04, 0x49, 0x23, 0x83, 0x86, 0x89, 0x57, 0x71, 0x08, 0x41,
+ 0x15, 0x97, 0x19, 0x72, 0x03, 0x27, 0x72, 0x52, 0x66, 0x67, 0x99, 0x15,
+ 0x33, 0x64, 0x69, 0x78, 0x07, 0x83, 0x53, 0x71, 0x21, 0x50, 0x05, 0x48,
+ 0x59, 0x85, 0x01, 0x36, 0x65, 0x02, 0x52, 0x01, 0x09, 0x49, 0x28, 0x77,
+ 0x25, 0x35, 0x67, 0x77, 0x81, 0x64, 0x24, 0x29, 0x42, 0x32, 0x59, 0x22,
+ 0x93, 0x48, 0x59, 0x03, 0x85, 0x87, 0x15, 0x55, 0x23, 0x42, 0x58, 0x17,
+ 0x18, 0x37, 0x70, 0x83, 0x80, 0x12, 0x44, 0x83, 0x45, 0x70, 0x55, 0x86,
+ 0x03, 0x23, 0x01, 0x56, 0x94, 0x12, 0x41, 0x34, 0x82, 0x90, 0x83, 0x46,
+ 0x17, 0x56, 0x66, 0x96, 0x75, 0x80, 0x59, 0x07, 0x15, 0x84, 0x19, 0x52,
+ 0x37, 0x44, 0x44, 0x83, 0x72, 0x43, 0x25, 0x42, 0x26, 0x86, 0x87, 0x86,
+ 0x91, 0x62, 0x14, 0x90, 0x34, 0x26, 0x14, 0x33, 0x59, 0x70, 0x73, 0x15,
+ 0x49, 0x40, 0x66, 0x88, 0x42, 0x66, 0x16, 0x42, 0x55, 0x92, 0x82, 0x06,
+ 0x20, 0x96, 0x36, 0x96, 0x13, 0x07, 0x84, 0x94, 0x37, 0x66, 0x62, 0x78,
+ 0x60, 0x58, 0x80, 0x50, 0x69, 0x03, 0x97, 0x16, 0x64, 0x45, 0x21, 0x39,
+ 0x79, 0x28, 0x52, 0x17, 0x14, 0x77, 0x31, 0x60, 0x86, 0x70, 0x09, 0x53,
+ 0x39, 0x32, 0x52, 0x31, 0x35, 0x79, 0x24, 0x70, 0x25, 0x48, 0x23, 0x49,
+ 0x10, 0x64, 0x54, 0x30, 0x82, 0x34, 0x51, 0x20, 0x46, 0x04, 0x29, 0x25,
+ 0x65, 0x09, 0x55, 0x30, 0x30, 0x52, 0x85, 0x32, 0x79, 0x19, 0x59, 0x07,
+ 0x05, 0x12, 0x11, 0x03, 0x21, 0x90, 0x36, 0x62, 0x23, 0x67, 0x36, 0x67,
+ 0x47, 0x39, 0x92, 0x88, 0x45, 0x43, 0x71, 0x16, 0x48, 0x27, 0x68, 0x39,
+ 0x98, 0x38, 0x03, 0x31, 0x85, 0x10, 0x06, 0x95, 0x54, 0x79, 0x28, 0x79,
+ 0x56, 0x16, 0x65, 0x69, 0x00, 0x54, 0x09, 0x91, 0x06, 0x10, 0x10, 0x86,
+ 0x75, 0x01, 0x02, 0x71, 0x01, 0x09, 0x32, 0x94, 0x66, 0x43, 0x68, 0x36,
+ 0x19, 0x52, 0x02, 0x04, 0x45, 0x49, 0x40, 0x94, 0x07, 0x87, 0x86, 0x79,
+ 0x84, 0x07, 0x75, 0x30, 0x73, 0x02, 0x57, 0x81, 0x65, 0x02, 0x28, 0x96,
+ 0x57, 0x07, 0x70, 0x34, 0x39, 0x35, 0x75, 0x19, 0x47, 0x57, 0x08, 0x75,
+ 0x86, 0x57, 0x11, 0x32, 0x09, 0x47, 0x83, 0x93, 0x20, 0x94, 0x90, 0x88,
+ 0x39, 0x63, 0x22, 0x88, 0x54, 0x54, 0x95, 0x75, 0x67, 0x26, 0x02, 0x49,
+ 0x26, 0x17, 0x35, 0x16, 0x27, 0x65, 0x64, 0x26, 0x93, 0x92, 0x77, 0x85,
+ 0x84, 0x40, 0x59, 0x29, 0x49, 0x69, 0x94, 0x71, 0x72, 0x21, 0x55, 0x03,
+ 0x19, 0x74, 0x09, 0x40, 0x57, 0x68, 0x41, 0x19, 0x11, 0x21, 0x63, 0x56,
+ 0x29, 0x77, 0x57, 0x81, 0x44, 0x40, 0x76, 0x77, 0x02, 0x71, 0x66, 0x35,
+ 0x89, 0x02, 0x64, 0x51, 0x61, 0x02, 0x46, 0x91, 0x38, 0x93, 0x62, 0x57,
+ 0x18, 0x98, 0x12, 0x87, 0x29, 0x48, 0x65, 0x39, 0x99, 0x45, 0x54, 0x69,
+ 0x51, 0x16, 0x25, 0x75, 0x60, 0x70, 0x33, 0x72, 0x01, 0x60, 0x26, 0x51,
+ 0x44, 0x14, 0x39, 0x12, 0x95, 0x48, 0x87, 0x33, 0x90, 0x16, 0x42, 0x78,
+ 0x48, 0x58, 0x96, 0x93, 0x75, 0x23, 0x07, 0x13, 0x86, 0x07, 0x96, 0x30,
+ 0x22, 0x82, 0x91, 0x36, 0x72, 0x16, 0x48, 0x77, 0x64, 0x99, 0x07, 0x34,
+ 0x78, 0x60, 0x61, 0x13, 0x48, 0x93, 0x46, 0x62, 0x48, 0x38, 0x37, 0x96,
+ 0x58, 0x64, 0x39, 0x90, 0x69, 0x46, 0x81, 0x98, 0x61, 0x89, 0x15, 0x59,
+ 0x78, 0x98, 0x21, 0x34, 0x00, 0x69, 0x97, 0x80, 0x28, 0x81, 0x53, 0x49,
+ 0x79, 0x53, 0x92, 0x20, 0x29, 0x40, 0x70, 0x06, 0x09, 0x55, 0x99, 0x41,
+ 0x51, 0x35, 0x55, 0x27, 0x39, 0x06, 0x29, 0x83, 0x66, 0x03, 0x68, 0x14,
+ 0x11, 0x69, 0x95, 0x51, 0x71, 0x55, 0x24, 0x60, 0x52, 0x58, 0x88, 0x11,
+ 0x88, 0x25, 0x37, 0x86, 0x01, 0x52, 0x93, 0x52, 0x02, 0x24, 0x91, 0x58,
+ 0x56, 0x37, 0x50, 0x88, 0x39, 0x09, 0x61, 0x19, 0x08, 0x86, 0x29, 0x51,
+ 0x63, 0x38, 0x81, 0x14, 0x75, 0x75, 0x39, 0x99, 0x22, 0x04, 0x32, 0x63,
+ 0x14, 0x68, 0x41, 0x79, 0x09, 0x57, 0x87, 0x29, 0x26, 0x94, 0x05, 0x71,
+ 0x82, 0x41, 0x26, 0x98, 0x68, 0x18, 0x55, 0x42, 0x78, 0x05, 0x74, 0x17,
+ 0x34, 0x34, 0x07, 0x62, 0x94, 0x72, 0x21, 0x08, 0x54, 0x72, 0x21, 0x08,
+ 0x31, 0x53, 0x82, 0x35, 0x27, 0x40, 0x85, 0x77, 0x08, 0x52, 0x58, 0x48,
+ 0x03, 0x86, 0x65, 0x51, 0x96, 0x43, 0x89, 0x19, 0x15, 0x08, 0x49, 0x62,
+ 0x57, 0x46, 0x17, 0x68, 0x56, 0x04, 0x70, 0x63, 0x75, 0x88, 0x13, 0x27,
+ 0x87, 0x44, 0x46, 0x27, 0x02, 0x97, 0x71, 0x07, 0x40, 0x17, 0x24, 0x61,
+ 0x16, 0x94, 0x86, 0x85, 0x67, 0x58, 0x87, 0x92, 0x02, 0x84, 0x75, 0x19,
+ 0x43, 0x60, 0x68, 0x03, 0x54, 0x75, 0x33, 0x17, 0x97, 0x75, 0x12, 0x62,
+ 0x43, 0x08, 0x35, 0x75, 0x32, 0x21, 0x08, 0x82, 0x78, 0x04, 0x74, 0x09,
+ 0x13, 0x48, 0x63, 0x68, 0x67, 0x09, 0x08, 0x50, 0x11, 0x71, 0x64, 0x72,
+ 0x63, 0x76, 0x21, 0x62, 0x80, 0x57, 0x19, 0x15, 0x26, 0x88, 0x02, 0x26,
+ 0x83, 0x17, 0x61, 0x76, 0x28, 0x10, 0x22, 0x37, 0x56, 0x71, 0x51, 0x60,
+ 0x12, 0x79, 0x24, 0x83, 0x78, 0x47, 0x78, 0x20, 0x52, 0x27, 0x19, 0x88,
+ 0x81, 0x04, 0x70, 0x20, 0x25, 0x10, 0x04, 0x01, 0x72, 0x57, 0x30, 0x93,
+ 0x96, 0x23, 0x02, 0x94, 0x61, 0x44, 0x17, 0x65, 0x77, 0x60, 0x27, 0x43,
+ 0x24, 0x59, 0x46, 0x76, 0x00, 0x11, 0x31, 0x99, 0x41, 0x48, 0x75, 0x32,
+ 0x05, 0x15, 0x45, 0x31, 0x57, 0x89, 0x10, 0x47, 0x53, 0x14, 0x66, 0x54,
+ 0x60, 0x55, 0x36, 0x93, 0x30, 0x03, 0x63, 0x80, 0x65, 0x43, 0x17, 0x36,
+ 0x18, 0x64, 0x21, 0x38, 0x16, 0x19, 0x19, 0x51, 0x73, 0x80, 0x38, 0x27,
+ 0x30, 0x89, 0x13, 0x43, 0x54, 0x11, 0x78, 0x05, 0x24, 0x38, 0x83, 0x56,
+ 0x50, 0x59, 0x12, 0x47, 0x69, 0x70, 0x70, 0x91, 0x28, 0x02, 0x08, 0x91,
+ 0x66, 0x09, 0x31, 0x65, 0x46, 0x20, 0x04, 0x85, 0x89, 0x53, 0x91, 0x42,
+ 0x34, 0x09, 0x36, 0x92, 0x42, 0x06, 0x87, 0x88, 0x23, 0x54, 0x87, 0x85,
+ 0x52, 0x98, 0x95, 0x76, 0x13, 0x50, 0x59, 0x89, 0x18, 0x14, 0x17, 0x47,
+ 0x10, 0x97, 0x39, 0x14, 0x33, 0x79, 0x83, 0x62, 0x55, 0x18, 0x30, 0x83,
+ 0x03, 0x45, 0x38, 0x37, 0x35, 0x20, 0x94, 0x84, 0x89, 0x80, 0x89, 0x10,
+ 0x48, 0x77, 0x33, 0x36, 0x50, 0x07, 0x93, 0x02, 0x45, 0x42, 0x91, 0x12,
+ 0x98, 0x09, 0x77, 0x20, 0x31, 0x95, 0x10, 0x29, 0x89, 0x02, 0x38, 0x92,
+ 0x90, 0x19, 0x51, 0x10, 0x19, 0x82, 0x23, 0x68, 0x06, 0x00, 0x67, 0x50,
+ 0x25, 0x03, 0x41, 0x69, 0x53, 0x42, 0x23, 0x99, 0x29, 0x21, 0x63, 0x22,
+ 0x72, 0x54, 0x72, 0x40, 0x23, 0x39, 0x74, 0x92, 0x53, 0x28, 0x67, 0x56,
+ 0x46, 0x84, 0x59, 0x85, 0x10, 0x92, 0x31, 0x20, 0x39, 0x95, 0x65, 0x15,
+ 0x76, 0x35, 0x37, 0x21, 0x98, 0x41, 0x68, 0x74, 0x94, 0x94, 0x86, 0x90,
+ 0x35, 0x07, 0x06, 0x38, 0x78, 0x32, 0x00, 0x60, 0x86, 0x12, 0x34, 0x65,
+ 0x67, 0x35, 0x76, 0x94, 0x78, 0x22, 0x99, 0x42, 0x82, 0x40, 0x05, 0x74,
+ 0x18, 0x59, 0x03, 0x83, 0x89, 0x05, 0x19, 0x28, 0x88, 0x35, 0x59, 0x10,
+ 0x12, 0x96, 0x48, 0x67, 0x59, 0x87, 0x26, 0x85, 0x74, 0x64, 0x78, 0x56,
+ 0x91, 0x81, 0x45, 0x90, 0x21, 0x80, 0x32, 0x19, 0x61, 0x38, 0x61, 0x70,
+ 0x35, 0x08, 0x93, 0x53, 0x21, 0x95, 0x08, 0x27, 0x90, 0x28, 0x94, 0x27,
+ 0x35, 0x78, 0x03, 0x57, 0x74, 0x84, 0x73, 0x63, 0x27, 0x98, 0x14, 0x21,
+ 0x22, 0x36, 0x75, 0x31, 0x81, 0x65, 0x85, 0x51, 0x02, 0x45, 0x18, 0x06,
+ 0x39, 0x13, 0x29, 0x29, 0x73, 0x26, 0x99, 0x51, 0x38, 0x43, 0x35, 0x58,
+ 0x70, 0x92, 0x32, 0x13, 0x80, 0x16, 0x26, 0x44, 0x22, 0x28, 0x05, 0x45,
+ 0x86, 0x90, 0x38, 0x19, 0x40, 0x06, 0x30, 0x56, 0x94, 0x09, 0x02, 0x02,
+ 0x96, 0x29, 0x22, 0x44, 0x87, 0x38, 0x09, 0x95, 0x58, 0x46, 0x42, 0x78,
+ 0x72, 0x77, 0x86, 0x31, 0x97, 0x19, 0x86, 0x51, 0x73, 0x76, 0x63, 0x98,
+ 0x39, 0x40, 0x20, 0x20, 0x67, 0x42, 0x55, 0x50, 0x63, 0x76, 0x81, 0x87,
+ 0x13, 0x81, 0x19, 0x54, 0x11, 0x77, 0x90, 0x26, 0x47, 0x25, 0x92, 0x88,
+ 0x18, 0x56, 0x23, 0x73, 0x91, 0x52, 0x39, 0x08, 0x59, 0x51, 0x81, 0x57,
+ 0x78, 0x17, 0x13, 0x90, 0x90, 0x50, 0x65, 0x59, 0x99, 0x77, 0x42, 0x28,
+ 0x21, 0x59, 0x97, 0x64, 0x25, 0x17, 0x92, 0x24, 0x50, 0x00, 0x28, 0x40,
+ 0x85, 0x33, 0x78, 0x86, 0x79, 0x40, 0x28, 0x30, 0x14, 0x12, 0x01, 0x72,
+ 0x41, 0x43, 0x06, 0x87, 0x67, 0x31, 0x66, 0x77, 0x07, 0x50, 0x55, 0x50,
+ 0x22, 0x80, 0x42, 0x06, 0x38, 0x01, 0x63, 0x66, 0x70, 0x12, 0x52, 0x91,
+ 0x90, 0x97, 0x21, 0x28, 0x22, 0x65, 0x02, 0x80, 0x72, 0x31, 0x17, 0x76,
+ 0x35, 0x16, 0x03, 0x56, 0x59, 0x93, 0x36, 0x37, 0x67, 0x54, 0x46, 0x87,
+ 0x29, 0x01, 0x30, 0x80, 0x47, 0x47, 0x31, 0x98, 0x34, 0x30, 0x23, 0x86,
+ 0x86, 0x14, 0x05, 0x75, 0x09, 0x88, 0x77, 0x92, 0x59, 0x43, 0x98, 0x72,
+ 0x55, 0x54, 0x25, 0x59, 0x22, 0x27, 0x21, 0x62, 0x97, 0x10, 0x61, 0x73,
+ 0x86, 0x95, 0x99, 0x10, 0x62, 0x35, 0x25, 0x16, 0x62, 0x60, 0x51, 0x48,
+ 0x69, 0x69, 0x92, 0x27, 0x19, 0x43, 0x40, 0x52, 0x70, 0x23, 0x37, 0x28,
+ 0x73, 0x10, 0x32, 0x55, 0x85, 0x46, 0x97, 0x59, 0x88, 0x48, 0x54, 0x06,
+ 0x58, 0x04, 0x82, 0x98, 0x88, 0x34, 0x05, 0x41, 0x94, 0x44, 0x35, 0x10,
+ 0x96, 0x48, 0x21, 0x17, 0x24, 0x40, 0x26, 0x15, 0x49, 0x28, 0x12, 0x17,
+ 0x10, 0x17, 0x91, 0x42, 0x84, 0x15, 0x83, 0x36, 0x29, 0x49, 0x92, 0x77,
+ 0x74, 0x11, 0x72, 0x97, 0x64, 0x53, 0x23, 0x29, 0x16, 0x35, 0x22, 0x10,
+ 0x87, 0x07, 0x44, 0x78, 0x18, 0x19, 0x79, 0x03, 0x58, 0x24, 0x15, 0x63,
+ 0x55, 0x75, 0x56, 0x14, 0x63, 0x65, 0x86, 0x61, 0x92, 0x94, 0x30, 0x92,
+ 0x69, 0x78, 0x40, 0x95, 0x19, 0x81, 0x41, 0x66, 0x97, 0x00, 0x17, 0x37,
+ 0x20, 0x82, 0x14, 0x26, 0x42, 0x63, 0x84, 0x20, 0x96, 0x11, 0x68, 0x37,
+ 0x60, 0x28, 0x69, 0x85, 0x45, 0x04, 0x62, 0x20, 0x49, 0x39, 0x74, 0x84,
+ 0x60, 0x23, 0x38, 0x33, 0x42, 0x49, 0x38, 0x82, 0x30, 0x63, 0x21, 0x51,
+ 0x69, 0x09, 0x05, 0x55, 0x78, 0x90, 0x68, 0x69, 0x22, 0x20, 0x17, 0x26,
+ 0x54, 0x01, 0x10, 0x04, 0x68, 0x19, 0x88, 0x40, 0x91, 0x74, 0x81, 0x29,
+ 0x07, 0x45, 0x33, 0x77, 0x12, 0x47, 0x08, 0x60, 0x09, 0x42, 0x84, 0x15,
+ 0x63, 0x92, 0x64, 0x77, 0x07, 0x44, 0x11, 0x07, 0x79, 0x81, 0x24, 0x05,
+ 0x21, 0x60, 0x81, 0x70, 0x66, 0x36, 0x69, 0x68, 0x45, 0x01, 0x11, 0x95,
+ 0x67, 0x95, 0x55, 0x07, 0x96, 0x63, 0x84, 0x04, 0x74, 0x72, 0x61, 0x91,
+ 0x60, 0x09, 0x90, 0x14, 0x34, 0x94, 0x06, 0x12, 0x01, 0x94, 0x40, 0x14,
+ 0x12, 0x53, 0x64, 0x81, 0x75, 0x99, 0x36, 0x99, 0x11, 0x69, 0x95, 0x51,
+ 0x71, 0x55, 0x24, 0x60, 0x52, 0x58, 0x88, 0x11, 0x88, 0x25, 0x37, 0x86,
+ 0x66, 0x36, 0x69, 0x68, 0x45, 0x01, 0x11, 0x95
+};
+
+struct cipher_parameter_map {
+ enum rte_crypto_cipher_algorithm algo;
+ int key_size;
+ int buffer_size;
+
+ uint8_t *ciphertext;
+ uint8_t *key;
+ uint8_t *iv;
+};
+
+struct cipher_parameter_map cmap;
+
+struct auth_parameter_map {
+ enum rte_crypto_auth_algorithm algo;
+ unsigned int key_size;
+
+ int buffer_size;
+
+ uint8_t *key;
+ uint8_t *aad;
+ uint8_t *digest;
+};
+
+struct auth_parameter_map amap;
+
+struct cperf_test_vector*
+cperf_test_vector_get(struct cperf_options *options)
+{
+ struct cperf_test_vector *t_vec;
+
+ t_vec = (struct cperf_test_vector *)rte_malloc(NULL,
+ sizeof(struct cperf_test_vector), 0);
+ if (t_vec == NULL)
+ return t_vec;
+
+ t_vec->plaintext.data = plaintext;
+ t_vec->plaintext.length = options->buffer_sz;
+
+
+ if (options->op_type == CPERF_CIPHER_ONLY ||
+ options->op_type == CPERF_CIPHER_THEN_AUTH ||
+ options->op_type == CPERF_AUTH_THEN_CIPHER ||
+ options->op_type == CPERF_AEAD) {
+ cmap.algo = options->cipher_algo;
+ if (options->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
+ cmap.key_size = -1;
+ cmap.buffer_size = -1;
+ cmap.ciphertext = plaintext;
+ cmap.key = NULL;
+ cmap.iv = NULL;
+ } else {
+ cmap.key_size = options->cipher_key_sz;
+ cmap.buffer_size = -1;
+ cmap.ciphertext = ciphertext;
+ cmap.key = cipher_key;
+ cmap.iv = iv;
+ }
+
+ t_vec->ciphertext.data = cmap.ciphertext;
+ t_vec->ciphertext.length = options->buffer_sz;
+
+ t_vec->cipher_key.data = cmap.key;
+ t_vec->cipher_key.length = cmap.key_size;
+
+ t_vec->iv.data = rte_malloc(NULL, options->cipher_iv_sz, 16);
+ t_vec->iv.phys_addr = rte_malloc_virt2phy(t_vec->iv.data);
+ t_vec->iv.length = options->cipher_iv_sz;
+
+ if (cmap.iv)
+ memcpy(t_vec->iv.data, cmap.iv, options->cipher_iv_sz);
+
+ t_vec->data.cipher_offset = 0;
+ t_vec->data.cipher_length = options->buffer_sz;
+ }
+
+ if (options->op_type == CPERF_AUTH_ONLY ||
+ options->op_type == CPERF_CIPHER_THEN_AUTH ||
+ options->op_type == CPERF_AUTH_THEN_CIPHER ||
+ options->op_type == CPERF_AEAD) {
+
+ amap.algo = options->auth_algo;
+ amap.key_size = options->auth_key_sz;
+ amap.buffer_size = options->buffer_sz;
+ if (options->auth_algo == RTE_CRYPTO_AUTH_NULL) {
+ amap.key = NULL;
+ amap.aad = NULL;
+ } else if (options->auth_algo == RTE_CRYPTO_AUTH_AES_GCM) {
+ amap.key = NULL;
+ amap.aad = aad;
+ } else {
+ amap.key = auth_key;
+ amap.aad = NULL;
+ }
+
+ switch (options->buffer_sz) {
+ case 32:
+ amap.digest = digest_32;
+ break;
+ case 64:
+ amap.digest = digest_64;
+ break;
+ case 128:
+ amap.digest = digest_128;
+ break;
+ case 256:
+ amap.digest = digest_256;
+ break;
+ case 384:
+ amap.digest = digest_384;
+ break;
+ case 512:
+ amap.digest = digest_512;
+ break;
+ case 768:
+ amap.digest = digest_768;
+ break;
+ case 1024:
+ amap.digest = digest_1024;
+ break;
+ case 1280:
+ amap.digest = digest_1280;
+ break;
+ case 1536:
+ amap.digest = digest_1536;
+ break;
+ case 1792:
+ amap.digest = digest_1792;
+ break;
+ case 2048:
+ amap.digest = digest_2048;
+ break;
+ }
+
+ t_vec->auth_key.data = amap.key;
+ t_vec->auth_key.length = amap.key_size;
+
+ t_vec->aad.data = rte_malloc(NULL, options->auth_aad_sz, 16);
+ t_vec->aad.phys_addr = rte_malloc_virt2phy(t_vec->aad.data);
+ t_vec->aad.length = options->auth_aad_sz;
+
+ if (amap.aad)
+ memcpy(t_vec->aad.data, amap.aad, options->auth_aad_sz);
+
+ t_vec->digest.data = rte_malloc(NULL, options->auth_digest_sz,
+ 16);
+ t_vec->digest.phys_addr =
+ rte_malloc_virt2phy(t_vec->digest.data);
+ t_vec->digest.length = options->auth_digest_sz;
+
+ if (amap.digest) {
+ memcpy(t_vec->digest.data, amap.digest,
+ options->auth_digest_sz);
+ }
+
+ t_vec->data.auth_offset = 0;
+ t_vec->data.auth_length = options->buffer_sz;
+ }
+
+ return t_vec;
+}
diff --git a/app/crypto-perf/cperf_test_vectors.h b/app/crypto-perf/cperf_test_vectors.h
new file mode 100644
index 0000000..80df4ac
--- /dev/null
+++ b/app/crypto-perf/cperf_test_vectors.h
@@ -0,0 +1,110 @@
+/*-
+ * 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 _CPERF_TEST_VECTRORS_
+#define _CPERF_TEST_VECTRORS_
+
+#include "cperf_options.h"
+
+struct cperf_test_vector {
+ struct {
+ uint8_t *data;
+ uint32_t length;
+ } plaintext;
+
+ struct {
+ uint8_t *data;
+ uint32_t length;
+ } cipher_key;
+
+ struct {
+ uint8_t *data;
+ uint32_t length;
+ } auth_key;
+
+ struct {
+ uint8_t *data;
+ phys_addr_t phys_addr;
+ uint32_t length;
+ } iv;
+
+ struct {
+ uint8_t *data;
+ uint32_t length;
+ } ciphertext;
+
+ struct {
+ uint8_t *data;
+ phys_addr_t phys_addr;
+ uint32_t length;
+ } aad;
+
+ struct {
+ uint8_t *data;
+ phys_addr_t phys_addr;
+ uint32_t length;
+ } digest;
+
+ struct {
+ uint32_t auth_offset;
+ uint32_t auth_length;
+ uint32_t cipher_offset;
+ uint32_t cipher_length;
+ } data;
+};
+
+struct cperf_test_vector*
+cperf_test_vector_get(struct cperf_options *options);
+
+
+extern uint8_t ciphertext[2048];
+
+extern uint8_t cipher_key[];
+extern uint8_t auth_key[];
+
+extern uint8_t iv[];
+extern uint8_t aad[];
+
+extern uint8_t digest_32[];
+extern uint8_t digest_64[];
+extern uint8_t digest_128[];
+extern uint8_t digest_256[];
+extern uint8_t digest_384[];
+extern uint8_t digest_512[];
+extern uint8_t digest_768[];
+extern uint8_t digest_1024[];
+extern uint8_t digest_1280[];
+extern uint8_t digest_1536[];
+extern uint8_t digest_1792[];
+extern uint8_t digest_2048[];
+
+#endif
diff --git a/app/crypto-perf/cperf_vectors_all.c b/app/crypto-perf/cperf_vectors_all.c
new file mode 100644
index 0000000..f7a5302
--- /dev/null
+++ b/app/crypto-perf/cperf_vectors_all.c
@@ -0,0 +1,238 @@
+#include <rte_crypto.h>
+#include <rte_malloc.h>
+
+#include "cperf_test_vectors.h"
+
+/* cipher text */
+uint8_t ciphertext[2048] = {
+ 0xE2, 0x19, 0x24, 0x56, 0x13, 0x59, 0xA6, 0x5D, 0xDF, 0xD0, 0x72, 0xAA,
+ 0x23, 0xC7, 0x36, 0x3A, 0xBB, 0x3E, 0x8B, 0x64, 0xD5, 0xBF, 0xDE, 0x65,
+ 0xA2, 0x75, 0xD9, 0x45, 0x6C, 0x3C, 0xD2, 0x6A, 0xC7, 0xD0, 0x9A, 0xD0,
+ 0x87, 0xB8, 0xE4, 0x94, 0x11, 0x62, 0x5A, 0xC3, 0xC3, 0x01, 0xA3, 0x86,
+ 0xBC, 0xBC, 0x9C, 0xC0, 0x81, 0x9F, 0xBF, 0x5C, 0x6F, 0x3F, 0x13, 0xF1,
+ 0xAE, 0xCF, 0x26, 0xB3, 0xBC, 0x49, 0xD6, 0x3B, 0x7A, 0x2E, 0x99, 0x9E,
+ 0x1B, 0x04, 0x50, 0x6C, 0x48, 0x6B, 0x4E, 0x72, 0xFC, 0xC8, 0xA7, 0x0C,
+ 0x2C, 0xD9, 0xED, 0xE4, 0x82, 0xC4, 0x81, 0xA6, 0xB4, 0xCC, 0xAD, 0x10,
+ 0xF3, 0x1C, 0x39, 0x05, 0x41, 0x2D, 0x57, 0x32, 0xE7, 0x16, 0xF8, 0x4D,
+ 0xF0, 0xDE, 0x40, 0x5B, 0x5F, 0x80, 0xDC, 0xA7, 0xC3, 0x2D, 0x3D, 0x9E,
+ 0x27, 0xD4, 0xE8, 0x10, 0x8E, 0xEB, 0xA5, 0x68, 0x6F, 0x3D, 0xC0, 0x44,
+ 0xE7, 0x77, 0x73, 0xB9, 0x92, 0x8E, 0xA2, 0x26, 0x5C, 0x6F, 0x33, 0x4B,
+ 0x0B, 0xEF, 0x37, 0x55, 0xBE, 0xEC, 0x98, 0x83, 0x1E, 0xDF, 0xB2, 0x9E,
+ 0x5D, 0x1D, 0x78, 0x14, 0xD7, 0x85, 0x0E, 0xF8, 0x12, 0x30, 0x8E, 0x5D,
+ 0x08, 0x77, 0x0B, 0x2E, 0x9B, 0xF9, 0xA6, 0x72, 0xD2, 0x41, 0xC1, 0x8E,
+ 0x6B, 0x5E, 0x11, 0x85, 0x22, 0x6E, 0xE4, 0xA3, 0xEA, 0x4C, 0x91, 0xE1,
+ 0x7D, 0xD0, 0xEB, 0x9F, 0xD9, 0xD7, 0x05, 0x77, 0xD9, 0xA1, 0xC2, 0xFD,
+ 0x41, 0x63, 0x51, 0xB4, 0x7A, 0x1F, 0x21, 0xF0, 0xBF, 0x11, 0x4D, 0x9B,
+ 0x97, 0xAB, 0xB4, 0x94, 0x36, 0x34, 0xC9, 0x2D, 0x8B, 0xE2, 0x61, 0xCF,
+ 0xAF, 0x69, 0xD5, 0x5C, 0xE9, 0xED, 0xE3, 0xA0, 0x69, 0xD3, 0xE5, 0xAE,
+ 0x67, 0x6C, 0xC7, 0x11, 0xB1, 0x21, 0x96, 0xD6, 0xDB, 0xA8, 0x1D, 0xC9,
+ 0x83, 0x0B, 0xE2, 0xC6, 0x6E, 0x94, 0xE9, 0x50, 0x12, 0x9B, 0x01, 0x72,
+ 0xAA, 0xFD, 0x8B, 0x7C, 0xEC, 0x0D, 0x01, 0xA4, 0x5D, 0x00, 0xE9, 0x79,
+ 0x58, 0xF5, 0x67, 0xF9, 0x61, 0xC3, 0x11, 0xB4, 0x7E, 0x76, 0x0A, 0x4C,
+ 0x60, 0xD6, 0xBD, 0xC8, 0x31, 0xD3, 0x0C, 0xD0, 0x5B, 0xDF, 0x7B, 0x05,
+ 0x9A, 0xBB, 0xC6, 0x2E, 0x9F, 0xF8, 0x18, 0x80, 0x6D, 0x1B, 0x21, 0xE5,
+ 0xAC, 0x75, 0xBC, 0x0D, 0x72, 0x51, 0x61, 0xD7, 0xEA, 0xA2, 0xAC, 0x0E,
+ 0xC1, 0xE7, 0x49, 0x37, 0xE7, 0x7C, 0xDE, 0xBD, 0x56, 0x00, 0x44, 0x6D,
+ 0xAB, 0x81, 0x2B, 0x26, 0x4A, 0xAA, 0x60, 0xE6, 0x43, 0x8D, 0x88, 0x1C,
+ 0x48, 0x55, 0x53, 0x25, 0xE8, 0x3C, 0x46, 0xF0, 0xA6, 0x33, 0x2D, 0xA2,
+ 0xDC, 0x99, 0x57, 0x38, 0x59, 0xCF, 0x53, 0xFA, 0x3E, 0x78, 0x46, 0xA0,
+ 0xA9, 0x50, 0x12, 0x72, 0xAC, 0x15, 0xC6, 0xA7, 0x42, 0x0F, 0x59, 0x6E,
+ 0xEA, 0xB0, 0x3D, 0xB8, 0x94, 0x32, 0xD1, 0xB6, 0xE8, 0x90, 0x06, 0x66,
+ 0x0C, 0xDE, 0xA9, 0x35, 0xC7, 0xDD, 0x72, 0x42, 0x38, 0x33, 0x32, 0x2F,
+ 0x2C, 0x3F, 0xBD, 0x01, 0xD6, 0x47, 0xFC, 0x89, 0x31, 0x38, 0x2E, 0xB9,
+ 0x6B, 0xED, 0xDB, 0x85, 0x38, 0xB1, 0xA5, 0x50, 0xFA, 0xFB, 0xA7, 0x31,
+ 0xEC, 0xB6, 0xBB, 0x82, 0x50, 0xB4, 0x88, 0x5C, 0xED, 0xE5, 0x4B, 0x5B,
+ 0xBF, 0xB3, 0x18, 0xFB, 0xAD, 0x24, 0x41, 0x55, 0x80, 0xCD, 0xA3, 0xA1,
+ 0xD6, 0xD5, 0xB6, 0x06, 0xE9, 0x85, 0x12, 0x33, 0x52, 0x56, 0xF1, 0xB7,
+ 0xDC, 0x57, 0x9E, 0xB4, 0x00, 0x1E, 0xCB, 0x62, 0x13, 0x4C, 0x90, 0x9A,
+ 0x9D, 0x64, 0x80, 0xD1, 0x5E, 0xB3, 0xCB, 0x8A, 0x73, 0x4E, 0x7B, 0xBE,
+ 0x4D, 0xA7, 0xF7, 0xB7, 0x9C, 0x1C, 0x7F, 0x27, 0x1E, 0x7F, 0x58, 0xB2,
+ 0x74, 0xAF, 0x94, 0x0E, 0x19, 0x23, 0xE1, 0x6B, 0xD8, 0x20, 0x4F, 0x2C,
+ 0x13, 0xE8, 0x8C, 0x37, 0x46, 0x27, 0x55, 0x68, 0xDA, 0x3F, 0x7A, 0xC6,
+ 0xEF, 0x87, 0x1D, 0x3B, 0x95, 0x43, 0x5E, 0x75, 0xE0, 0x02, 0x22, 0x0E,
+ 0x11, 0x60, 0xAB, 0x1A, 0x91, 0x94, 0xC4, 0xFA, 0xD9, 0x92, 0x2B, 0xE5,
+ 0x03, 0xE0, 0x7A, 0x17, 0x5C, 0x67, 0x22, 0xB3, 0xCB, 0x77, 0x9E, 0x22,
+ 0x01, 0x5F, 0x5D, 0x64, 0xE4, 0x2F, 0xC4, 0x61, 0xCA, 0xC7, 0xFD, 0x20,
+ 0x24, 0x30, 0xAB, 0x3F, 0x1A, 0x08, 0x85, 0x08, 0x39, 0xDE, 0x19, 0x1C,
+ 0x1A, 0xEA, 0xB8, 0x7E, 0xE5, 0xBC, 0xD9, 0xB2, 0x59, 0xC8, 0x81, 0x02,
+ 0x1D, 0x5C, 0xC0, 0xDD, 0x8D, 0x56, 0xB6, 0x2E, 0x85, 0x26, 0xA8, 0x34,
+ 0x92, 0x36, 0x9A, 0x84, 0xBD, 0x27, 0xC1, 0x9D, 0x5E, 0x14, 0xC4, 0xB7,
+ 0x02, 0xA8, 0xC9, 0xC2, 0xAD, 0xDC, 0x98, 0x42, 0x51, 0xDE, 0x94, 0x28,
+ 0x39, 0xEF, 0xE9, 0x7F, 0x05, 0x3F, 0x1D, 0x67, 0x72, 0x04, 0xCF, 0x7D,
+ 0x38, 0x49, 0xC4, 0x59, 0xA5, 0xF6, 0xB6, 0x02, 0x31, 0xD0, 0x05, 0x74,
+ 0x4B, 0xD0, 0x89, 0xD1, 0x7F, 0xC6, 0xDB, 0x7E, 0x75, 0x62, 0xA3, 0xC2,
+ 0x2E, 0xB0, 0xCC, 0x9A, 0xD3, 0xA4, 0x14, 0xB6, 0xF2, 0x91, 0x44, 0x3F,
+ 0x84, 0xE0, 0x90, 0x4A, 0x6A, 0x34, 0x8C, 0x35, 0x3C, 0xB2, 0xA9, 0x35,
+ 0x88, 0xB0, 0x88, 0xF8, 0x7E, 0x5C, 0xD2, 0x08, 0x5E, 0x08, 0x15, 0x03,
+ 0xBC, 0xF5, 0x42, 0x6B, 0x28, 0xED, 0xDD, 0xAA, 0x4D, 0x78, 0x10, 0x31,
+ 0x32, 0xA2, 0xC5, 0xCA, 0xEE, 0x9A, 0x62, 0x52, 0x3E, 0x48, 0x83, 0xA4,
+ 0xCA, 0xD4, 0xC7, 0xA7, 0xA5, 0x3F, 0x44, 0x1C, 0x86, 0xAD, 0x52, 0x7D,
+ 0x80, 0x1D, 0x9E, 0x32, 0x3F, 0x2A, 0x2E, 0xD8, 0x89, 0xC1, 0xA4, 0xD6,
+ 0xC1, 0x90, 0x2E, 0x1A, 0x20, 0x4B, 0x87, 0x32, 0x35, 0x25, 0xD8, 0xB8,
+ 0x57, 0x15, 0x85, 0x1E, 0x3C, 0x8A, 0xDC, 0x1A, 0x49, 0x3D, 0x70, 0x35,
+ 0x99, 0xAA, 0xDE, 0x2C, 0xD4, 0xAF, 0x79, 0x72, 0xAB, 0x97, 0x84, 0x20,
+ 0xB6, 0x4F, 0x34, 0x3F, 0xEA, 0xAE, 0x5F, 0x8F, 0x3A, 0x42, 0xDB, 0x68,
+ 0xE5, 0x84, 0x63, 0x2E, 0x7A, 0x0E, 0xBD, 0x28, 0x6A, 0x24, 0xB6, 0xAB,
+ 0xE4, 0xAC, 0x20, 0x7C, 0x81, 0xD0, 0x69, 0x89, 0xF8, 0xDE, 0xA9, 0x02,
+ 0xFD, 0x1F, 0x08, 0xDA, 0x26, 0xC2, 0x24, 0xCA, 0xEB, 0x44, 0x16, 0x8D,
+ 0x55, 0x5F, 0xB9, 0xA9, 0x5A, 0x18, 0x50, 0xB1, 0x54, 0xF1, 0xBF, 0x06,
+ 0xC2, 0xB0, 0x95, 0xC2, 0xAE, 0xE5, 0xBF, 0xB3, 0xFD, 0xC9, 0xBF, 0x75,
+ 0x42, 0x7D, 0xA0, 0xA8, 0x95, 0xF9, 0x62, 0x3B, 0x9C, 0x0D, 0x81, 0xF3,
+ 0x9C, 0xFC, 0x19, 0x5B, 0xF7, 0xD1, 0x9C, 0xF0, 0xAA, 0xFE, 0xEF, 0x35,
+ 0x1E, 0x81, 0x9E, 0x02, 0x46, 0x52, 0x9B, 0x99, 0x0D, 0x12, 0x8B, 0x71,
+ 0x6C, 0x32, 0xB5, 0x23, 0x17, 0x03, 0xC5, 0xB0, 0xA1, 0xC3, 0x4B, 0x10,
+ 0x01, 0x4D, 0x4C, 0x4A, 0x46, 0x8F, 0xD9, 0x79, 0xBB, 0x10, 0x44, 0xB0,
+ 0x3C, 0x7D, 0x46, 0xFD, 0x38, 0xDF, 0xAF, 0x6E, 0x58, 0x7D, 0xE1, 0xEB,
+ 0xBB, 0x8C, 0xDC, 0x79, 0xDA, 0x41, 0xD1, 0x8B, 0x0B, 0x11, 0x4F, 0xE5,
+ 0x1C, 0xC1, 0x59, 0xA7, 0x1E, 0x5A, 0xC1, 0xEE, 0x27, 0x33, 0xC8, 0x55,
+ 0xA9, 0x32, 0xEA, 0xF7, 0x45, 0xB0, 0x08, 0xE9, 0x32, 0xDF, 0x70, 0x24,
+ 0x82, 0xD3, 0x2A, 0x3E, 0x4F, 0x42, 0xB9, 0x25, 0x10, 0xD1, 0x73, 0xFA,
+ 0xFD, 0xC1, 0x84, 0xF2, 0xF7, 0x0E, 0xBC, 0x9D, 0x90, 0x39, 0xD7, 0xFD,
+ 0x45, 0x77, 0xBA, 0x29, 0xF9, 0x87, 0x45, 0xC1, 0x32, 0x44, 0xB0, 0x27,
+ 0x6B, 0xFC, 0x8A, 0xFE, 0x00, 0x6F, 0x61, 0x98, 0xD0, 0x60, 0xC8, 0x10,
+ 0xE5, 0xBC, 0x88, 0x13, 0x45, 0x44, 0xA5, 0xEB, 0x6E, 0xCB, 0x11, 0xAF,
+ 0x30, 0xDC, 0x8B, 0xF8, 0x30, 0x46, 0xDA, 0x76, 0xF1, 0xE5, 0x14, 0x51,
+ 0x8A, 0x02, 0x5A, 0x5A, 0xAA, 0x7B, 0x2D, 0x57, 0x0A, 0x5C, 0x73, 0xD1,
+ 0x88, 0xCE, 0xBE, 0x3D, 0x06, 0x3F, 0x48, 0x1D, 0x44, 0x24, 0x6F, 0x4F,
+ 0x7F, 0x6A, 0xF2, 0x16, 0x34, 0x35, 0x38, 0x73, 0x8A, 0xE5, 0x25, 0xF4,
+ 0x34, 0x9E, 0x5B, 0x40, 0x90, 0x04, 0x57, 0x1B, 0x57, 0x75, 0x8F, 0xEA,
+ 0x1C, 0xF8, 0x7A, 0x68, 0x01, 0x1C, 0x8D, 0xBA, 0xF4, 0xE3, 0xD3, 0x8F,
+ 0x7F, 0xE4, 0x50, 0x35, 0x6B, 0x6B, 0xF6, 0xFC, 0x5F, 0x9B, 0x98, 0x78,
+ 0x16, 0x68, 0x72, 0x74, 0x71, 0x78, 0x25, 0x68, 0xE5, 0x1E, 0x66, 0xE2,
+ 0x4E, 0xC8, 0xDB, 0x92, 0x8E, 0x88, 0x64, 0x74, 0xDE, 0xDB, 0x85, 0x56,
+ 0x9F, 0xF9, 0xC4, 0x29, 0x54, 0xA8, 0xFB, 0xBA, 0xEA, 0xAB, 0xC7, 0x49,
+ 0x5C, 0x6C, 0xD7, 0x61, 0x8C, 0xE2, 0x2B, 0xF5, 0xA0, 0xA8, 0xD2, 0x41,
+ 0xC0, 0x54, 0xAB, 0xA7, 0x56, 0x5C, 0xE7, 0xA5, 0xEA, 0xBC, 0x47, 0xD1,
+ 0x0D, 0xD9, 0xC0, 0xA9, 0xC4, 0xA7, 0x3E, 0xD1, 0x2B, 0x1E, 0x34, 0x31,
+ 0x36, 0x9D, 0xB9, 0x51, 0xD3, 0xAD, 0x29, 0xE6, 0x9B, 0xD8, 0x4B, 0x93,
+ 0x33, 0x2F, 0x30, 0xEF, 0x18, 0x90, 0x69, 0x11, 0x09, 0xEA, 0xBA, 0xE0,
+ 0x10, 0x93, 0x63, 0x71, 0xA8, 0x83, 0x59, 0xDB, 0xFC, 0x12, 0x22, 0x84,
+ 0xC7, 0x01, 0x20, 0x99, 0xEC, 0x59, 0xA9, 0xE6, 0x9B, 0x5B, 0x8B, 0xB8,
+ 0x68, 0x52, 0x61, 0x8B, 0x4E, 0xF3, 0x50, 0x69, 0xF1, 0x49, 0x9B, 0xAF,
+ 0x53, 0xAD, 0xA0, 0x9D, 0x23, 0xE0, 0xE0, 0xC4, 0x31, 0xE4, 0x8E, 0x1C,
+ 0x51, 0x14, 0xFC, 0x95, 0x9C, 0xA6, 0x34, 0x85, 0xB0, 0x36, 0xFC, 0x7A,
+ 0x53, 0x03, 0x31, 0x0E, 0xCB, 0x34, 0x3E, 0xDF, 0xD1, 0x71, 0xBC, 0xDB,
+ 0xA1, 0xAF, 0x59, 0x4A, 0x03, 0x19, 0xA7, 0x8E, 0xB5, 0x82, 0x15, 0x24,
+ 0x69, 0x68, 0xBD, 0x9C, 0x2E, 0xFA, 0x06, 0xB5, 0x70, 0xC5, 0x70, 0xC4,
+ 0x14, 0x99, 0x01, 0x49, 0xBD, 0x6E, 0xAE, 0x10, 0xA1, 0xE4, 0xEF, 0xDD,
+ 0xE5, 0x51, 0x22, 0x9D, 0xF7, 0x93, 0xAB, 0x41, 0xBD, 0x86, 0x7A, 0xCC,
+ 0x51, 0x94, 0xEC, 0x22, 0xBE, 0x0D, 0x67, 0xFD, 0xA3, 0xFD, 0xCF, 0xF8,
+ 0x74, 0x0A, 0x5E, 0x1C, 0x71, 0xAD, 0xB6, 0xD0, 0xD7, 0xF8, 0x71, 0x34,
+ 0xAB, 0x62, 0xE7, 0xA8, 0x6B, 0x8F, 0x1E, 0x43, 0x46, 0xA5, 0xE4, 0xB4,
+ 0x52, 0x81, 0x66, 0xB3, 0xE5, 0x10, 0x23, 0x21, 0x2B, 0x31, 0x0F, 0xB8,
+ 0xB6, 0xC5, 0xA5, 0xC9, 0x90, 0x07, 0x83, 0xD0, 0xC3, 0x10, 0x7A, 0x04,
+ 0xBD, 0x8A, 0x3C, 0x7B, 0xF9, 0x0E, 0x51, 0x81, 0x96, 0xC8, 0xAE, 0xF9,
+ 0x27, 0xDE, 0x62, 0x7A, 0x41, 0x60, 0x35, 0x8F, 0x77, 0xBC, 0x95, 0x11,
+ 0x2C, 0xC4, 0x6C, 0x47, 0x7A, 0xEB, 0x29, 0xE5, 0x8E, 0xB5, 0xD6, 0xA5,
+ 0x54, 0x1B, 0xD0, 0xE0, 0x0F, 0x7D, 0x5C, 0x51, 0xD8, 0x6C, 0x92, 0x2F,
+ 0x13, 0x4E, 0x90, 0x77, 0xF8, 0x8D, 0x69, 0x78, 0x96, 0x96, 0x49, 0x9F,
+ 0x3C, 0x2E, 0x5C, 0xA6, 0x73, 0x27, 0x7D, 0xAD, 0x8D, 0xE3, 0x9B, 0x4A,
+ 0x2F, 0x50, 0x0A, 0x42, 0x7E, 0xF2, 0x3B, 0x50, 0x5C, 0x81, 0xC9, 0x49,
+ 0x01, 0x96, 0x83, 0x0A, 0xEC, 0x7F, 0xED, 0x1C, 0xA5, 0x7D, 0xF1, 0xE6,
+ 0xC4, 0xB3, 0x8F, 0xF9, 0x0F, 0xDB, 0x7B, 0xC1, 0x35, 0xF7, 0x63, 0x4A,
+ 0x39, 0xD4, 0x0E, 0x9E, 0x05, 0xD9, 0x42, 0xAA, 0xAB, 0x52, 0xCA, 0x4E,
+ 0x98, 0x3B, 0x43, 0x1A, 0x91, 0x25, 0xA9, 0x34, 0xD5, 0x66, 0xB2, 0xF4,
+ 0xFF, 0xDE, 0x64, 0x91, 0x90, 0xB9, 0x17, 0x70, 0xA0, 0xD6, 0xEA, 0xB6,
+ 0x36, 0xF4, 0x44, 0xCE, 0x86, 0x7B, 0x18, 0x74, 0x9C, 0x18, 0xAD, 0xB6,
+ 0xE0, 0x74, 0xC1, 0x0E, 0x29, 0x5D, 0x6A, 0x36, 0xD1, 0x3E, 0xB8, 0x2A,
+ 0xE4, 0x23, 0x1D, 0xB2, 0xAE, 0xF5, 0x5B, 0x8E, 0x2C, 0xD9, 0xD1, 0xE1,
+ 0x4F, 0x58, 0xA6, 0xE3, 0x88, 0x2E, 0xF9, 0xCF, 0x32, 0x3E, 0x8E, 0x37,
+ 0x95, 0xFF, 0xAD, 0x68, 0x11, 0x5E, 0x7F, 0x3D, 0x38, 0x06, 0x7C, 0x33,
+ 0x32, 0x78, 0x09, 0xEC, 0xCA, 0x3E, 0x08, 0xF1, 0xD0, 0x95, 0x19, 0xC9,
+ 0x7E, 0x62, 0xB2, 0x02, 0xA3, 0x5D, 0xF8, 0x3F, 0xA2, 0xB0, 0x8B, 0x38,
+ 0xB1, 0x8C, 0xEA, 0xB3, 0xE4, 0xBF, 0xD3, 0x6C, 0x6D, 0x3D, 0xD1, 0xC6,
+ 0xDA, 0x6B, 0x7A, 0xBA, 0x05, 0xEA, 0x9E, 0xA5, 0xE9, 0x00, 0xCC, 0x80,
+ 0x57, 0xAB, 0xD9, 0x0A, 0xD1, 0x00, 0x82, 0x2A, 0x51, 0x4B, 0xA2, 0x96,
+ 0xEB, 0x96, 0x14, 0xA8, 0x46, 0xDF, 0x1D, 0x48, 0xAE, 0xFA, 0x12, 0xA8,
+ 0x89, 0x8E, 0xEF, 0xBC, 0x3C, 0xA1, 0x6E, 0xDD, 0x90, 0x66, 0x2E, 0x56,
+ 0x6B, 0xF7, 0x1D, 0xF0, 0x46, 0x11, 0x4A, 0xA6, 0x07, 0x73, 0xC4, 0xE3,
+ 0x97, 0xFE, 0x7E, 0x22, 0x6F, 0x22, 0xB4, 0x6F, 0xB0, 0x32, 0x0A, 0x5E,
+ 0x85, 0x7E, 0x54, 0xB4, 0x24, 0xBD, 0x36, 0xA7, 0x94, 0xE7, 0x37, 0xFD,
+ 0x1A, 0xAF, 0xF4, 0x44, 0xB4, 0x35, 0x4F, 0xE0, 0x41, 0x0E, 0x7D, 0x73,
+ 0x29, 0x28, 0xDA, 0xAF, 0x69, 0xB2, 0xC5, 0xA7, 0x2A, 0x0A, 0xB5, 0x9C,
+ 0xC2, 0xAC, 0x5F, 0x59, 0x5C, 0xEE, 0x44, 0x49, 0x6F, 0x4F, 0x64, 0x43,
+ 0x6F, 0x43, 0x44, 0xAA, 0xA0, 0x4E, 0x94, 0x7C, 0x26, 0x5A, 0xF1, 0xD9,
+ 0xE6, 0x09, 0x80, 0x7A, 0x7D, 0x2E, 0xA2, 0xB9, 0x1A, 0x7A, 0x8F, 0x2A,
+ 0x97, 0x77, 0x23, 0xB4, 0x10, 0xAD, 0x20, 0x7B, 0xA3, 0x0F, 0xFD, 0x44,
+ 0x38, 0xAD, 0x94, 0x39, 0x88, 0x1C, 0xC4, 0xC8, 0xDF, 0xF1, 0x04, 0xA6,
+ 0x51, 0x5D, 0x54, 0x53, 0x60, 0xE4, 0x8A, 0x89, 0x4A, 0x9C, 0xE1, 0x68,
+ 0x4D, 0xFE, 0x69, 0x94, 0x0B, 0x8E, 0xED, 0x6C, 0xFE, 0x11, 0xA7, 0x77,
+ 0xBF, 0x08, 0x41, 0x67, 0x22, 0x59, 0x51, 0x48, 0xEE, 0x59, 0x02, 0x0E,
+ 0x60, 0x6D, 0xAE, 0x8C, 0xC6, 0x39, 0xB7, 0x55, 0xC5, 0x3B, 0x87, 0xA9,
+ 0xBD, 0xD8, 0xEA, 0x48, 0x21, 0xE4, 0x57, 0x51, 0x56, 0x03, 0xF4, 0xBE,
+ 0xBD, 0xBD, 0xC5, 0x26, 0x9B, 0x27, 0xE3, 0xAE, 0xD5, 0x1E, 0x30, 0xE9,
+ 0x7C, 0x9D, 0xDB, 0xE1, 0x09, 0x9D, 0x82, 0x49, 0x15, 0x38, 0x69, 0xFC,
+ 0x1D, 0x52, 0x1A, 0x75, 0xE6, 0xDD, 0x1D, 0xBE, 0x06, 0xC4, 0x9F, 0x14,
+ 0x4C, 0x12, 0xDE, 0xDF, 0x4A, 0xE1, 0x3B, 0xE7, 0xD1, 0xE3, 0x71, 0xD1,
+ 0xFA, 0xD8, 0x0E, 0x63, 0x27, 0xA9, 0xC7, 0x9D, 0xC0, 0x01, 0xC2, 0xDD,
+ 0xFC, 0xA6, 0x1F, 0x59, 0x87, 0xC5, 0x56, 0x99, 0x80, 0xEB, 0xF0, 0xB8,
+ 0xB3, 0x00, 0x9A, 0x61, 0xDB, 0x50, 0x79, 0x48, 0x37, 0x35, 0xDA, 0xD8,
+ 0xF2, 0x37, 0xA7, 0x43, 0xA7, 0xEB, 0x88, 0x2C, 0x68, 0xB4, 0xBB, 0x14,
+ 0x45, 0x31, 0x6B, 0x87, 0x65, 0xE7, 0x82, 0xB4, 0x74, 0xD2, 0xFF, 0x7F,
+ 0x60, 0x15, 0x94, 0x75, 0xEE, 0x30, 0x3C, 0x4E, 0xFC, 0x41, 0xD1, 0x5B,
+ 0xDD, 0x84, 0x6E, 0x13, 0x6C, 0xF8, 0x12, 0xE6, 0xB7, 0xA4, 0xB9, 0xC8,
+ 0x13, 0x89, 0x0C, 0x34, 0xA6, 0xAF, 0x09, 0xEB, 0xF2, 0xB3, 0x79, 0x77,
+ 0x80, 0xD8, 0x77, 0x64, 0xAD, 0x32, 0x3D, 0xD2, 0x06, 0xDF, 0x72, 0x11,
+ 0x4A, 0xA7, 0x70, 0xCE, 0xF9, 0xE6, 0x81, 0x35, 0xA4, 0xA7, 0x52, 0xB5,
+ 0x13, 0x68, 0x5C, 0x69, 0x45, 0xE2, 0x77, 0x2D, 0xBE, 0x2C, 0xE9, 0x38,
+ 0x25, 0x28, 0x7B, 0x63, 0x2C, 0x19, 0x8F, 0x59
+};
+
+/* aad */
+uint8_t aad[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
+};
+
+/* iv */
+uint8_t iv[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F
+};
+
+/* cipher key */
+uint8_t cipher_key[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+};
+
+/* auth key */
+uint8_t auth_key[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
+ 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+ 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B,
+ 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F
+};
+
+/* Digests */
+uint8_t digest_32[] = { 0x0 };
+
+uint8_t digest_64[] = { 0x0 };
+
+uint8_t digest_128[] = { 0x00 };
+
+uint8_t digest_256[] = { 0x00 };
+
+uint8_t digest_384[] = { 0x00 };
+
+uint8_t digest_512[] = { 0x00 };
+
+uint8_t digest_768[] = { 0x00 };
+
+uint8_t digest_1024[] = { 0x00 };
+
+uint8_t digest_1280[] = { 0x00 };
+
+uint8_t digest_1536[] = { 0x00 };
+
+uint8_t digest_1792[] = { 0x00 };
+
+uint8_t digest_2048[] = { 0x00 };
+
diff --git a/app/crypto-perf/main.c b/app/crypto-perf/main.c
new file mode 100644
index 0000000..8698c44
--- /dev/null
+++ b/app/crypto-perf/main.c
@@ -0,0 +1,291 @@
+#include <stdio.h>
+#include <unistd.h>
+
+#include <rte_eal.h>
+#include <rte_cryptodev.h>
+
+#include "cperf.h"
+#include "cperf_options.h"
+#include "cperf_test_throughput.h"
+#include "cperf_test_latency.h"
+
+const char *cperf_test_type_strs[] = {
+ [CPERF_TEST_TYPE_THROUGHPUT] = "throughput",
+ [CPERF_TEST_TYPE_CYCLECOUNT] = "cycle-count",
+ [CPERF_TEST_TYPE_LATENCY] = "latency"
+};
+
+const char *cperf_op_type_strs[] = {
+ [CPERF_CIPHER_ONLY] = "cipher-only",
+ [CPERF_AUTH_ONLY] = "auth-only",
+ [CPERF_CIPHER_THEN_AUTH] = "cipher-then-auth",
+ [CPERF_AUTH_THEN_CIPHER] = "auth-then-cipher",
+ [CPERF_AEAD] = "aead"
+};
+
+
+
+const struct cperf_test cperf_testmap[] = {
+ [CPERF_TEST_TYPE_THROUGHPUT] = {
+ cperf_throughput_test_constructor,
+ cperf_throughput_test_runner,
+ cperf_throughput_test_destructor
+ },
+ [CPERF_TEST_TYPE_CYCLECOUNT] = { NULL },
+ [CPERF_TEST_TYPE_LATENCY] = {
+ cperf_latency_test_constructor,
+ cperf_latency_test_runner,
+ cperf_latency_test_destructor
+ }
+};
+
+static int
+cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs)
+{
+ uint8_t cdev_id, enabled_cdev_count = 0, nb_lcores;
+ int ret;
+
+ enabled_cdev_count = rte_cryptodev_devices_get(opts->device_type,
+ enabled_cdevs, RTE_DIM(enabled_cdevs));
+ if (enabled_cdev_count == 0) {
+ printf("No crypto devices type %s available\n",
+ opts->device_type);
+ return -EINVAL;
+ }
+
+ nb_lcores = rte_lcore_count() - 1;
+
+ if (enabled_cdev_count > nb_lcores) {
+ printf("Number of capable crypto devices (%d) "
+ "has to be less or equal to number of slave "
+ "cores (%d)\n", enabled_cdev_count, nb_lcores);
+ return -EINVAL;
+ }
+
+ for (cdev_id = 0; cdev_id < enabled_cdev_count &&
+ cdev_id < RTE_CRYPTO_MAX_DEVS; cdev_id++) {
+
+ struct rte_cryptodev_config conf = {
+ .nb_queue_pairs = 1,
+ .socket_id = SOCKET_ID_ANY,
+ .session_mp = {
+ .nb_objs = 2048,
+ .cache_size = 64
+ }
+ };
+ struct rte_cryptodev_qp_conf qp_conf = {
+ .nb_descriptors = 2048
+ };
+
+ ret = rte_cryptodev_configure(enabled_cdevs[cdev_id], &conf);
+ if (ret < 0) {
+ printf("Failed to configure cryptodev %u",
+ enabled_cdevs[cdev_id]);
+ return -EINVAL;
+ }
+
+ ret = rte_cryptodev_queue_pair_setup(enabled_cdevs[cdev_id], 0,
+ &qp_conf, SOCKET_ID_ANY);
+ if (ret < 0) {
+ printf("Failed to setup queue pair %u on "
+ "cryptodev %u", 0, cdev_id);
+ return -EINVAL;
+ }
+
+ ret = rte_cryptodev_start(enabled_cdevs[cdev_id]);
+ if (ret < 0) {
+ printf("Failed to start device %u: error %d\n",
+ enabled_cdevs[cdev_id], ret);
+ return -EPERM;
+ }
+ }
+
+ return enabled_cdev_count;
+}
+
+static int
+cperf_verify_devices_capabilities(struct cperf_options *opts,
+ uint8_t *enabled_cdevs, uint8_t nb_cryptodevs)
+{
+ struct rte_cryptodev_capbility_idx cap_idx;
+ const struct rte_cryptodev_symmetric_capability *capability;
+
+ uint8_t i, cdev_id;
+ int ret;
+
+ for (i = 0; i < nb_cryptodevs; i++) {
+
+ cdev_id = enabled_cdevs[i];
+
+ if (opts->op_type == CPERF_AUTH_ONLY ||
+ opts->op_type == CPERF_CIPHER_THEN_AUTH ||
+ opts->op_type == CPERF_AUTH_THEN_CIPHER) {
+
+ cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH;
+ cap_idx.algo.auth = opts->auth_algo;
+
+ capability = rte_cryptodev_capbility_get(cdev_id,
+ &cap_idx);
+ if (capability == NULL)
+ return -1;
+
+ ret = rte_cryptodev_capability_check_auth(capability,
+ opts->auth_key_sz, opts->auth_digest_sz,
+ opts->auth_aad_sz);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (opts->op_type == CPERF_CIPHER_ONLY ||
+ opts->op_type == CPERF_CIPHER_THEN_AUTH ||
+ opts->op_type == CPERF_AUTH_THEN_CIPHER) {
+
+ cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+ cap_idx.algo.cipher = opts->cipher_algo;
+
+ capability = rte_cryptodev_capbility_get(cdev_id,
+ &cap_idx);
+ if (capability == NULL)
+ return -1;
+
+ ret = rte_cryptodev_capability_check_cipher(capability,
+ opts->cipher_key_sz,
+ opts->cipher_iv_sz);
+ if (ret != 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct cperf_options opts;
+ struct cperf_test_vector *t_vec;
+ const struct cperf_op_fns *op_fns;
+
+ void *ctx[RTE_MAX_LCORE] = { };
+
+ uint8_t nb_cryptodevs, cdev_id, i;
+ uint8_t enabled_cdevs[RTE_CRYPTO_MAX_DEVS] = { 0 };
+
+ int ret;
+ uint32_t lcore_id;
+
+ /* Initialise DPDK EAL */
+ ret = rte_eal_init(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid EAL arguments!\n");
+ argc -= ret;
+ argv += ret;
+
+ cperf_options_default(&opts);
+
+ ret = cperf_options_parse(&opts, argc, argv);
+ if (ret) {
+ RTE_LOG(ERR, USER1, "Parsing on or more user options failed\n");
+ goto err;
+ }
+
+ ret = cperf_options_check(&opts);
+ if (ret) {
+ RTE_LOG(ERR, USER1,
+ "Checking on or more user options failed\n");
+ goto err;
+ }
+
+ if (!opts.silent)
+ cperf_options_dump(&opts);
+
+ nb_cryptodevs = cperf_initialize_cryptodev(&opts, enabled_cdevs);
+ if (nb_cryptodevs < 1) {
+ RTE_LOG(ERR, USER1, "Failed to initialise requested crypto "
+ "device type\n");
+ goto err;
+ }
+
+ ret = cperf_verify_devices_capabilities(&opts, enabled_cdevs,
+ nb_cryptodevs);
+ if (ret) {
+ RTE_LOG(ERR, USER1, "Crypto device type does not support "
+ "capabilities requested\n");
+ goto err;
+ }
+
+ t_vec = cperf_test_vector_get(&opts);
+ if (t_vec == NULL) {
+ RTE_LOG(ERR, USER1, "Failed to find test vector for specified"
+ " algorithms\n");
+ goto err;
+ }
+
+ op_fns = cperf_get_op_functions(&opts);
+ if (op_fns == NULL) {
+ RTE_LOG(ERR, USER1, "Failed to find function ops set for "
+ "specified algorithms combination\n");
+ goto err;
+ }
+
+ i = 0;
+ RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+
+ if (i == nb_cryptodevs)
+ break;
+
+ cdev_id = enabled_cdevs[i];
+
+ ctx[cdev_id] = cperf_testmap[opts.test].constructor(cdev_id, 0,
+ &opts, t_vec, op_fns);
+ if (ctx[cdev_id] == NULL) {
+ RTE_LOG(ERR, USER1, "Test run constructor failed\n");
+ goto err;
+ }
+ i++;
+ }
+
+ i = 0;
+ RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+
+ if (i == nb_cryptodevs)
+ break;
+
+ cdev_id = enabled_cdevs[i];
+
+ rte_eal_remote_launch(cperf_testmap[opts.test].runner,
+ ctx[cdev_id], lcore_id);
+ i++;
+ }
+
+ rte_eal_mp_wait_lcore();
+
+ i = 0;
+ RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+
+ if (i == nb_cryptodevs)
+ break;
+
+ cdev_id = enabled_cdevs[i];
+
+ cperf_testmap[opts.test].desctructor(ctx[cdev_id]);
+ i++;
+ }
+
+ return EXIT_SUCCESS;
+
+err:
+ i = 0;
+ RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+
+ if (i == nb_cryptodevs)
+ break;
+
+ cdev_id = enabled_cdevs[i];
+
+ if (ctx[cdev_id] && cperf_testmap[opts.test].desctructor)
+ cperf_testmap[opts.test].desctructor(ctx[cdev_id]);
+ i++;
+ }
+ return EXIT_FAILURE;
+}
diff --git a/config/common_base b/config/common_base
index 4bff83a..30cf676 100644
--- a/config/common_base
+++ b/config/common_base
@@ -589,3 +589,9 @@ CONFIG_RTE_APP_TEST_RESOURCE_TAR=n
CONFIG_RTE_TEST_PMD=y
CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n
CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n
+
+#
+# Compile the crypto performance application
+#
+CONFIG_RTE_APP_CRYPTO_PERF=y
+
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH 2/2] crypto/aesni_mb: add new option to select SIMD mode
From: Declan Doherty @ 2016-12-02 16:05 UTC (permalink / raw)
To: Thomas Monjalon; +Cc: dev
In-Reply-To: <2408315.PI9TjJa4bq@xps13>
On 02/12/16 10:37, Thomas Monjalon wrote:
> 2016-12-02 09:46, Declan Doherty:
>> Add new initialisation option to the aesni_mb_pmd to allow the user to specify
>> which set of SIMD functions to load from the AESNI Multi-Buffer Crypto for IPsec
>> library.
>
> Why let user choose? Isn't the most recent the better?
>
> This PMD and other software crypto PMDs could (should?) override the CFLAGS
> like rte_acl do, in order to be able to use recent SIMD functions even if it
> was globally disabled by the compilation target.
> See my comment in the rte_memset thread.
>
In general yes, I was mainly using this to allow quick performance
comparisons between different platforms and different instruction sets
on the same platform without recompilation, but I admit that this is
probably not a normal end user use case.
I'll look at the CFLAGS options you mention and address in a V2.
^ permalink raw reply
* Re: [PATCH v2 3/7] pci: Pass rte_pci_addr to functions instead of separate args
From: Walker, Benjamin @ 2016-12-02 16:16 UTC (permalink / raw)
To: shreyansh.jain@nxp.com; +Cc: dev@dpdk.org
In-Reply-To: <abed91f3-d6e7-d850-1fd5-3fc3de4f7595@nxp.com>
On Thu, 2016-12-01 at 11:56 +0530, Shreyansh Jain wrote:
> Hello Ben,
>
> On Thursday 24 November 2016 01:37 AM, Ben Walker wrote:
> >
> > Instead of passing domain, bus, devid, func, just pass
> > an rte_pci_addr.
> >
> > Signed-off-by: Ben Walker <benjamin.walker@intel.com>
> > ---
> > lib/librte_eal/linuxapp/eal/eal_pci.c | 32 +++++++++++++-------------------
> > 1 file changed, 13 insertions(+), 19 deletions(-)
> >
> > diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c
> > b/lib/librte_eal/linuxapp/eal/eal_pci.c
> > index 876ba38..073af5f 100644
> > --- a/lib/librte_eal/linuxapp/eal/eal_pci.c
> > +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
> > @@ -267,8 +267,7 @@ pci_parse_sysfs_resource(const char *filename, struct
> > rte_pci_device *dev)
> >
> > /* Scan one pci sysfs entry, and fill the devices list from it. */
> > static int
> > -pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
> > - uint8_t devid, uint8_t function)
> > +pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
> > {
> > char filename[PATH_MAX];
> > unsigned long tmp;
> > @@ -281,10 +280,7 @@ pci_scan_one(const char *dirname, uint16_t domain,
> > uint8_t bus,
> > return -1;
> >
> > memset(dev, 0, sizeof(*dev));
> > - dev->addr.domain = domain;
> > - dev->addr.bus = bus;
> > - dev->addr.devid = devid;
> > - dev->addr.function = function;
> > + dev->addr = *addr;
> >
> > /* get vendor id */
> > snprintf(filename, sizeof(filename), "%s/vendor", dirname);
> > @@ -429,16 +425,14 @@ pci_update_device(const struct rte_pci_addr *addr)
> > pci_get_sysfs_path(), addr->domain, addr->bus, addr-
> > >devid,
> > addr->function);
> >
> > - return pci_scan_one(filename, addr->domain, addr->bus, addr->devid,
> > - addr->function);
> > + return pci_scan_one(filename, addr);
> > }
> >
> > /*
> > * split up a pci address into its constituent parts.
> > */
> > static int
> > -parse_pci_addr_format(const char *buf, int bufsize, uint16_t *domain,
> > - uint8_t *bus, uint8_t *devid, uint8_t *function)
> > +parse_pci_addr_format(const char *buf, int bufsize, struct rte_pci_addr
> > *addr)
> > {
> > /* first split on ':' */
> > union splitaddr {
> > @@ -466,10 +460,10 @@ parse_pci_addr_format(const char *buf, int bufsize,
> > uint16_t *domain,
> >
> > /* now convert to int values */
> > errno = 0;
> > - *domain = (uint16_t)strtoul(splitaddr.domain, NULL, 16);
> > - *bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
> > - *devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
> > - *function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
> > + addr->domain = (uint16_t)strtoul(splitaddr.domain, NULL, 16);
> > + addr->bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
> > + addr->devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
> > + addr->function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
> > if (errno != 0)
> > goto error;
> >
> > @@ -490,8 +484,7 @@ rte_eal_pci_scan(void)
> > struct dirent *e;
> > DIR *dir;
> > char dirname[PATH_MAX];
> > - uint16_t domain;
> > - uint8_t bus, devid, function;
> > + struct rte_pci_addr addr;
> >
> > dir = opendir(pci_get_sysfs_path());
> > if (dir == NULL) {
> > @@ -500,20 +493,21 @@ rte_eal_pci_scan(void)
> > return -1;
> > }
> >
> > +
> > while ((e = readdir(dir)) != NULL) {
> > if (e->d_name[0] == '.')
> > continue;
> >
> > - if (parse_pci_addr_format(e->d_name, sizeof(e->d_name),
> > &domain,
> > - &bus, &devid, &function) != 0)
> > + if (parse_pci_addr_format(e->d_name, sizeof(e->d_name),
> > &addr) != 0)
> > continue;
> >
> > snprintf(dirname, sizeof(dirname), "%s/%s",
> > pci_get_sysfs_path(), e->d_name);
> > - if (pci_scan_one(dirname, domain, bus, devid, function) <
> > 0)
> > + if (pci_scan_one(dirname, &addr) < 0)
> > goto error;
> > }
> > closedir(dir);
> > +
> > return 0;
> >
> > error:
> >
>
> Do you mind if I use this patch directly as part of my patchset for bus
> Model? I was doing a similar change to make the pci_scan_one simpler
> (and pass along a new argument)..
Sure, go ahead.
>
> -
> Shreyansh
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox