[v2,1/2] fips_validation: add SGL support

Message ID 20200904160945.24590-2-roy.fan.zhang@intel.com (mailing list archive)
State Superseded, archived
Delegated to: akhil goyal
Headers
Series fips_validation: add SGL and GMAC support |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Fan Zhang Sept. 4, 2020, 4:09 p.m. UTC
  This patch adds SGL support to FIPS sample application.
Originally the application allocates single mbuf of 64KB - 1
bytes data room. With the change the user may reduce the
mbuf dataroom size by using the add cmdline option. If the
input test data is longer than the user provided data room
size the application will automatically build chained mbufs
for the target cryptodev PMD to test.

Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 doc/guides/sample_app_ug/fips_validation.rst |   6 +
 examples/fips_validation/fips_validation.h   |   3 +-
 examples/fips_validation/main.c              | 377 +++++++++++++------
 3 files changed, 271 insertions(+), 115 deletions(-)
  

Comments

Suanming Mou Sept. 7, 2020, 1:32 p.m. UTC | #1
Hi,

On 9/5/2020 12:09 AM, Fan Zhang wrote:
> This patch adds SGL support to FIPS sample application.
> Originally the application allocates single mbuf of 64KB - 1
> bytes data room. With the change the user may reduce the
> mbuf dataroom size by using the add cmdline option. If the
> input test data is longer than the user provided data room
> size the application will automatically build chained mbufs
> for the target cryptodev PMD to test.
>
> Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
> ---
>   doc/guides/sample_app_ug/fips_validation.rst |   6 +
>   examples/fips_validation/fips_validation.h   |   3 +-
>   examples/fips_validation/main.c              | 377 +++++++++++++------
>   3 files changed, 271 insertions(+), 115 deletions(-)
>
> diff --git a/doc/guides/sample_app_ug/fips_validation.rst b/doc/guides/sample_app_ug/fips_validation.rst
> index 2953fddeb..8d3db2214 100644
> --- a/doc/guides/sample_app_ug/fips_validation.rst
> +++ b/doc/guides/sample_app_ug/fips_validation.rst
> @@ -96,6 +96,7 @@ The application requires a number of command line options:
>            -- --req-file FILE_PATH/FOLDER_PATH
>            --rsp-file FILE_PATH/FOLDER_PATH
>            [--cryptodev DEVICE_NAME] [--cryptodev-id ID] [--path-is-folder]
> +         --mbuf-dataroom DATAROOM_SIZE
>   
>   where,
>     * req-file: The path of the request file or folder, separated by
> @@ -111,6 +112,11 @@ where,
>     * path-is-folder: If presented the application expects req-file and rsp-file
>       are folder paths.
>   
> +  * mbuf-dataroom: By default the application creates mbuf pool with maximum
> +    possible data room (65535 bytes). If the user wants to test scatter-gather
> +    list feature of the PMD he or she may set this value to reduce the dataroom
> +    size so that the input data may be dividied into multiple chained mbufs.
> +
>   
>   To run the application in linux environment to test one AES FIPS test data
>   file for crypto_aesni_mb PMD, issue the command:
> diff --git a/examples/fips_validation/fips_validation.h b/examples/fips_validation/fips_validation.h
> index 75fa555fa..ecf3d54dd 100644
> --- a/examples/fips_validation/fips_validation.h
> +++ b/examples/fips_validation/fips_validation.h
> @@ -12,7 +12,8 @@
>   #define MAX_CASE_LINE		15
>   #define MAX_LINE_CHAR		204800 /*< max number of characters per line */
>   #define MAX_NB_TESTS		10240
> -#define MAX_BUF_SIZE		2048
> +#define DEF_MBUF_SEG_SIZE	(UINT16_MAX - sizeof(struct rte_mbuf) - \
> +				RTE_PKTMBUF_HEADROOM)
>   #define MAX_STRING_SIZE		64
>   #define MAX_DIGEST_SIZE		64
>   
> diff --git a/examples/fips_validation/main.c b/examples/fips_validation/main.c
> index efd32a86a..fadca6e0c 100644
> --- a/examples/fips_validation/main.c
> +++ b/examples/fips_validation/main.c
> @@ -17,6 +17,7 @@
>   
>   #define REQ_FILE_PATH_KEYWORD	"req-file"
>   #define RSP_FILE_PATH_KEYWORD	"rsp-file"
> +#define MBUF_DATAROOM_KEYWORD	"mbuf-dataroom"
>   #define FOLDER_KEYWORD		"path-is-folder"
>   #define CRYPTODEV_KEYWORD	"cryptodev"
>   #define CRYPTODEV_ID_KEYWORD	"cryptodev-id"
> @@ -33,15 +34,19 @@ struct cryptodev_fips_validate_env {
>   	const char *req_path;
>   	const char *rsp_path;
>   	uint32_t is_path_folder;
> -	uint32_t dev_id;
> +	uint8_t dev_id;
> +	uint8_t dev_support_sgl;
> +	uint16_t mbuf_data_room;
>   	struct rte_mempool *mpool;
>   	struct rte_mempool *sess_mpool;
>   	struct rte_mempool *sess_priv_mpool;
>   	struct rte_mempool *op_pool;
>   	struct rte_mbuf *mbuf;
> +	uint8_t *digest;
> +	uint16_t digest_len;
>   	struct rte_crypto_op *op;
>   	struct rte_cryptodev_sym_session *sess;
> -	uint32_t self_test;
> +	uint16_t self_test;
>   	struct fips_dev_broken_test_config *broken_test_config;
>   } env;
>   
> @@ -50,8 +55,10 @@ cryptodev_fips_validate_app_int(void)
>   {
>   	struct rte_cryptodev_config conf = {rte_socket_id(), 1, 0};
>   	struct rte_cryptodev_qp_conf qp_conf = {128, NULL, NULL};
> +	struct rte_cryptodev_info dev_info;
Better to initialize the dev_info here?
>   	uint32_t sess_sz = rte_cryptodev_sym_get_private_session_size(
>   			env.dev_id);
> +	uint32_t nb_mbufs = UINT16_MAX / env.mbuf_data_room + 1;
>   	int ret;
>   
>   	if (env.self_test) {
> @@ -70,8 +77,15 @@ cryptodev_fips_validate_app_int(void)
>   	if (ret < 0)
>   		return ret;
>   
> -	env.mpool = rte_pktmbuf_pool_create("FIPS_MEMPOOL", 128, 0, 0,
> -			UINT16_MAX, rte_socket_id());
> +	rte_cryptodev_info_get(env.dev_id, &dev_info);
> +	if (dev_info.feature_flags & RTE_CRYPTODEV_FF_IN_PLACE_SGL)
> +		env.dev_support_sgl = 1;
> +	else
> +		env.dev_support_sgl = 0;
> +
> +	env.mpool = rte_pktmbuf_pool_create("FIPS_MEMPOOL", nb_mbufs,
> +			0, 0, sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM +
> +			env.mbuf_data_room, rte_socket_id());
>   	if (!env.mpool)
>   		return ret;
>   
> @@ -102,10 +116,6 @@ cryptodev_fips_validate_app_int(void)
>   	if (!env.op_pool)
>   		goto error_exit;
>   
> -	env.mbuf = rte_pktmbuf_alloc(env.mpool);
> -	if (!env.mbuf)
> -		goto error_exit;
> -
>   	env.op = rte_crypto_op_alloc(env.op_pool, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
>   	if (!env.op)
>   		goto error_exit;
> @@ -160,7 +170,7 @@ parse_cryptodev_arg(char *arg)
>   		return id;
>   	}
>   
> -	env.dev_id = (uint32_t)id;
> +	env.dev_id = (uint8_t)id;
>   
>   	return 0;
>   }
> @@ -191,19 +201,21 @@ parse_cryptodev_id_arg(char *arg)
>   static void
>   cryptodev_fips_validate_usage(const char *prgname)
>   {
> +	uint32_t def_mbuf_seg_size = DEF_MBUF_SEG_SIZE;
>   	printf("%s [EAL options] --\n"
>   		"  --%s: REQUEST-FILE-PATH\n"
>   		"  --%s: RESPONSE-FILE-PATH\n"
>   		"  --%s: indicating both paths are folders\n"
> +		"  --%s: mbuf dataroom size (default %u bytes)\n"
>   		"  --%s: CRYPTODEV-NAME\n"
>   		"  --%s: CRYPTODEV-ID-NAME\n"
>   		"  --%s: self test indicator\n"
>   		"  --%s: self broken test ID\n"
>   		"  --%s: self broken test direction\n",
>   		prgname, REQ_FILE_PATH_KEYWORD, RSP_FILE_PATH_KEYWORD,
> -		FOLDER_KEYWORD, CRYPTODEV_KEYWORD, CRYPTODEV_ID_KEYWORD,
> -		CRYPTODEV_ST_KEYWORD, CRYPTODEV_BK_ID_KEYWORD,
> -		CRYPTODEV_BK_DIR_KEY);
> +		FOLDER_KEYWORD, MBUF_DATAROOM_KEYWORD, def_mbuf_seg_size,
> +		CRYPTODEV_KEYWORD, CRYPTODEV_ID_KEYWORD, CRYPTODEV_ST_KEYWORD,
> +		CRYPTODEV_BK_ID_KEYWORD, CRYPTODEV_BK_DIR_KEY);
>   }
>   
>   static int
> @@ -217,6 +229,7 @@ cryptodev_fips_validate_parse_args(int argc, char **argv)
>   			{REQ_FILE_PATH_KEYWORD, required_argument, 0, 0},
>   			{RSP_FILE_PATH_KEYWORD, required_argument, 0, 0},
>   			{FOLDER_KEYWORD, no_argument, 0, 0},
> +			{MBUF_DATAROOM_KEYWORD, required_argument, 0, 0},
>   			{CRYPTODEV_KEYWORD, required_argument, 0, 0},
>   			{CRYPTODEV_ID_KEYWORD, required_argument, 0, 0},
>   			{CRYPTODEV_ST_KEYWORD, no_argument, 0, 0},
> @@ -227,6 +240,14 @@ cryptodev_fips_validate_parse_args(int argc, char **argv)
>   
>   	argvopt = argv;
>   
> +	env.mbuf_data_room = DEF_MBUF_SEG_SIZE;
> +	if (rte_cryptodev_count())
> +		env.dev_id = 0;
> +	else {
> +		cryptodev_fips_validate_usage(prgname);
> +		return -EINVAL;
> +	}
> +
>   	while ((opt = getopt_long(argc, argvopt, "s:",
>   				  lgopts, &option_index)) != EOF) {
>   
> @@ -305,6 +326,23 @@ cryptodev_fips_validate_parse_args(int argc, char **argv)
>   					cryptodev_fips_validate_usage(prgname);
>   					return -EINVAL;
>   				}
> +			} else if (strcmp(lgopts[option_index].name,
> +					MBUF_DATAROOM_KEYWORD) == 0) {
> +				uint32_t data_room_size;
> +
> +				if (parser_read_uint32(&data_room_size,
> +						optarg) < 0) {
> +					cryptodev_fips_validate_usage(prgname);
> +					return -EINVAL;
> +				}
> +
> +				if (data_room_size == 0 ||
> +						data_room_size > UINT16_MAX) {
> +					cryptodev_fips_validate_usage(prgname);
> +					return -EINVAL;
> +				}
> +
> +				env.mbuf_data_room = data_room_size;
>   			} else {
>   				cryptodev_fips_validate_usage(prgname);
>   				return -EINVAL;
> @@ -315,8 +353,7 @@ cryptodev_fips_validate_parse_args(int argc, char **argv)
>   		}
>   	}
>   
> -	if (env.req_path == NULL || env.rsp_path == NULL ||
> -			env.dev_id == UINT32_MAX) {
> +	if (env.req_path == NULL || env.rsp_path == NULL) {
>   		cryptodev_fips_validate_usage(prgname);
>   		return -EINVAL;
>   	}
> @@ -451,60 +488,124 @@ struct fips_test_ops {
>   } test_ops;
>   
>   static int
> -prepare_cipher_op(void)
> +prepare_data_mbufs(struct fips_val *val)
>   {
> -	struct rte_crypto_sym_op *sym = env.op->sym;
> -	uint8_t *iv = rte_crypto_op_ctod_offset(env.op, uint8_t *, IV_OFF);
> +	struct rte_mbuf *m, *head = 0;
> +	uint8_t *src = val->val;
> +	uint32_t total_len = val->len;
> +	uint16_t nb_seg;
> +	int ret = 0;
>   
> -	__rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
> -	rte_pktmbuf_reset(env.mbuf);
> -
> -	sym->m_src = env.mbuf;
> -	sym->cipher.data.offset = 0;
> +	if (env.mbuf)
> +		rte_pktmbuf_free(env.mbuf);
>   
> -	memcpy(iv, vec.iv.val, vec.iv.len);
> +	if (total_len > RTE_MBUF_MAX_NB_SEGS) {
> +		RTE_LOG(ERR, USER1, "Data len %u too big\n", total_len);
> +		return -EPERM;
> +	}
>   
> -	if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
> -		uint8_t *pt;
> +	nb_seg = total_len / env.mbuf_data_room;
> +	if (total_len % env.mbuf_data_room)
> +		nb_seg++;
>   
> -		if (vec.pt.len > RTE_MBUF_MAX_NB_SEGS) {
> -			RTE_LOG(ERR, USER1, "PT len %u\n", vec.pt.len);
> -			return -EPERM;
> -		}
> +	m = rte_pktmbuf_alloc(env.mpool);
> +	if (!m) {
> +		RTE_LOG(ERR, USER1, "Error %i: Not enough mbuf\n",
> +				-ENOMEM);
> +		return -ENOMEM;
> +	}
> +	head = m;
>   
> -		pt = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.pt.len);
> +	while (nb_seg) {
> +		uint16_t len = RTE_MIN(total_len, env.mbuf_data_room);
> +		uint8_t *dst = (uint8_t *)rte_pktmbuf_append(m, len);
>   
> -		if (!pt) {
> +		if (!dst) {
>   			RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
>   					-ENOMEM);
> -			return -ENOMEM;
> +			ret = -ENOMEM;
> +			goto error_exit;
>   		}
>   
> -		memcpy(pt, vec.pt.val, vec.pt.len);
> -		sym->cipher.data.length = vec.pt.len;
> +		memcpy(dst, src, len);
>   
> -	} else {
> -		uint8_t *ct;
> -
> -		if (vec.ct.len > RTE_MBUF_MAX_NB_SEGS) {
> -			RTE_LOG(ERR, USER1, "CT len %u\n", vec.ct.len);
> -			return -EPERM;
> +		if (head != m) {
> +			ret = rte_pktmbuf_chain(head, m);
> +			if (ret) {
> +				rte_pktmbuf_free(m);
> +				RTE_LOG(ERR, USER1, "Error %i: SGL build\n",
> +						ret);
> +				goto error_exit;
> +			}
>   		}
> +		total_len -= len;
>   
> -		ct = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.ct.len);
> +		if (total_len) {
> +			if (!env.dev_support_sgl) {
> +				RTE_LOG(ERR, USER1, "SGL not supported\n");
> +				ret = -EPERM;
> +				goto error_exit;
> +			}
>   
> -		if (!ct) {
> -			RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
> -					-ENOMEM);
> -			return -ENOMEM;
> -		}
> +			m = rte_pktmbuf_alloc(env.mpool);
> +			if (!m) {
> +				RTE_LOG(ERR, USER1, "Error %i: No memory\n",
> +						-ENOMEM);
> +				goto error_exit;
> +			}
> +		} else
> +			break;
> +
> +		src += len;
> +		nb_seg--;
> +	}
> +
> +	if (total_len) {
> +		RTE_LOG(ERR, USER1, "Error %i: Failed to store all data\n",
> +				-ENOMEM);
> +		goto error_exit;
> +	}
> +
> +	env.mbuf = head;
> +
> +	return 0;
> +
> +error_exit:
> +	if (head)
> +		rte_pktmbuf_free(head);
> +	return ret;
> +}
> +
> +static int
> +prepare_cipher_op(void)
> +{
> +	struct rte_crypto_sym_op *sym = env.op->sym;
> +	uint8_t *iv = rte_crypto_op_ctod_offset(env.op, uint8_t *, IV_OFF);
> +	int ret;
> +
> +	__rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
> +
> +	memcpy(iv, vec.iv.val, vec.iv.len);
> +
> +	if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
> +		ret = prepare_data_mbufs(&vec.pt);
> +		if (ret < 0)
> +			return ret;
> +
> +		sym->cipher.data.length = vec.pt.len;
> +	} else {
> +		ret = prepare_data_mbufs(&vec.ct);
> +		if (ret < 0)
> +			return ret;
>   
> -		memcpy(ct, vec.ct.val, vec.ct.len);
>   		sym->cipher.data.length = vec.ct.len;
>   	}
>   
>   	rte_crypto_op_attach_sym_session(env.op, env.sess);
>   
> +	sym->m_src = env.mbuf;
> +	sym->cipher.data.offset = 0;
> +
>   	return 0;
>   }
>   
> @@ -512,32 +613,33 @@ static int
>   prepare_auth_op(void)
>   {
>   	struct rte_crypto_sym_op *sym = env.op->sym;
> -	uint8_t *pt;
> +	int ret;
>   
>   	__rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
> -	rte_pktmbuf_reset(env.mbuf);
>   
> -	sym->m_src = env.mbuf;
> -	sym->auth.data.offset = 0;
> +	ret = prepare_data_mbufs(&vec.pt);
> +	if (ret < 0)
> +		return ret;
>   
> -	pt = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.pt.len +
> -			vec.cipher_auth.digest.len);
> +	if (env.digest)
> +		rte_free(env.digest);
>   
> -	if (!pt) {
> -		RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
> -				-ENOMEM);
> +	env.digest = rte_zmalloc(NULL, vec.cipher_auth.digest.len,
> +			RTE_CACHE_LINE_SIZE);
> +	if (!env.digest) {
> +		RTE_LOG(ERR, USER1, "Not enough memory\n");
>   		return -ENOMEM;
>   	}
> +	env.digest_len = vec.cipher_auth.digest.len;
>   
> +	sym->m_src = env.mbuf;
> +	sym->auth.data.offset = 0;
>   	sym->auth.data.length = vec.pt.len;
> -	sym->auth.digest.data = pt + vec.pt.len;
> -	sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
> -			env.mbuf, vec.pt.len);
> -
> -	memcpy(pt, vec.pt.val, vec.pt.len);
> +	sym->auth.digest.data = env.digest;
> +	sym->auth.digest.phys_addr = rte_malloc_virt2iova(env.digest);
>   
>   	if (info.op == FIPS_TEST_DEC_AUTH_VERIF)
> -		memcpy(pt + vec.pt.len, vec.cipher_auth.digest.val,
> +		memcpy(env.digest, vec.cipher_auth.digest.val,
>   				vec.cipher_auth.digest.len);
>   
>   	rte_crypto_op_attach_sym_session(env.op, env.sess);
> @@ -550,65 +652,53 @@ prepare_aead_op(void)
>   {
>   	struct rte_crypto_sym_op *sym = env.op->sym;
>   	uint8_t *iv = rte_crypto_op_ctod_offset(env.op, uint8_t *, IV_OFF);
> +	int ret;
>   
>   	__rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
> -	rte_pktmbuf_reset(env.mbuf);
>   
>   	if (info.algo == FIPS_TEST_ALGO_AES_CCM)
> -		memcpy(iv + 1, vec.iv.val, vec.iv.len);
> -	else
> -		memcpy(iv, vec.iv.val, vec.iv.len);
> +		iv++;
>   
> -	sym->m_src = env.mbuf;
> -	sym->aead.data.offset = 0;
> -	sym->aead.aad.data = vec.aead.aad.val;
> -	sym->aead.aad.phys_addr = rte_malloc_virt2iova(sym->aead.aad.data);
> +	if (vec.iv.val)
> +		memcpy(iv, vec.iv.val, vec.iv.len);
> +	else
> +		/* if REQ file has iv length but not data, default as all 0 */
> +		memset(iv, 0, vec.iv.len);
>   
>   	if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
> -		uint8_t *pt;
> -
> -		if (vec.pt.len > RTE_MBUF_MAX_NB_SEGS) {
> -			RTE_LOG(ERR, USER1, "PT len %u\n", vec.pt.len);
> -			return -EPERM;
> -		}
> -
> -		pt = (uint8_t *)rte_pktmbuf_append(env.mbuf,
> -				vec.pt.len + vec.aead.digest.len);
> +		ret = prepare_data_mbufs(&vec.pt);
> +		if (ret < 0)
> +			return ret;
>   
> -		if (!pt) {
> -			RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
> -					-ENOMEM);
> +		if (env.digest)
> +			rte_free(env.digest);
> +		env.digest = rte_zmalloc(NULL, vec.aead.digest.len,
> +				RTE_CACHE_LINE_SIZE);
> +		if (!env.digest) {
> +			RTE_LOG(ERR, USER1, "Not enough memory\n");
>   			return -ENOMEM;
>   		}
> +		env.digest_len = vec.cipher_auth.digest.len;
>   
> -		memcpy(pt, vec.pt.val, vec.pt.len);
>   		sym->aead.data.length = vec.pt.len;
> -		sym->aead.digest.data = pt + vec.pt.len;
> -		sym->aead.digest.phys_addr = rte_pktmbuf_mtophys_offset(
> -				env.mbuf, vec.pt.len);
> +		sym->aead.digest.data = env.digest;
> +		sym->aead.digest.phys_addr = rte_malloc_virt2iova(env.digest);
>   	} else {
> -		uint8_t *ct;
> -
> -		if (vec.ct.len > RTE_MBUF_MAX_NB_SEGS) {
> -			RTE_LOG(ERR, USER1, "CT len %u\n", vec.ct.len);
> -			return -EPERM;
> -		}
> -
> -		ct = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.ct.len);
> -
> -		if (!ct) {
> -			RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
> -					-ENOMEM);
> -			return -ENOMEM;
> -		}
> +		ret = prepare_data_mbufs(&vec.ct);
> +		if (ret < 0)
> +			return ret;
>   
> -		memcpy(ct, vec.ct.val, vec.ct.len);
>   		sym->aead.data.length = vec.ct.len;
>   		sym->aead.digest.data = vec.aead.digest.val;
>   		sym->aead.digest.phys_addr = rte_malloc_virt2iova(
>   				sym->aead.digest.data);
>   	}
>   
> +	sym->m_src = env.mbuf;
> +	sym->aead.data.offset = 0;
> +	sym->aead.aad.data = vec.aead.aad.val;
> +	sym->aead.aad.phys_addr = rte_malloc_virt2iova(sym->aead.aad.data);
> +
>   	rte_crypto_op_attach_sym_session(env.op, env.sess);
>   
>   	return 0;
> @@ -952,11 +1042,48 @@ prepare_xts_xform(struct rte_crypto_sym_xform *xform)
>   	return 0;
>   }
>   
> -static void
> +static int
>   get_writeback_data(struct fips_val *val)
>   {
> -	val->val = rte_pktmbuf_mtod(env.mbuf, uint8_t *);
> -	val->len = rte_pktmbuf_pkt_len(env.mbuf);
> +	struct rte_mbuf *m = env.mbuf;
> +	uint16_t data_len = rte_pktmbuf_pkt_len(m);
> +	uint16_t total_len = data_len + env.digest_len;
> +	uint8_t *src, *dst, *wb_data;
> +
> +	/* in case val is reused for MCT test, try to free the buffer first */
> +	if (val->val) {
> +		free(val->val);
> +		val->val = NULL;
> +	}
> +
> +	wb_data = dst = calloc(1, total_len);
> +	if (!dst) {
> +		RTE_LOG(ERR, USER1, "Error %i: Not enough memory\n", -ENOMEM);
> +		return -ENOMEM;
> +	}
> +
> +	while (m && data_len) {
> +		uint16_t seg_len = RTE_MIN(rte_pktmbuf_data_len(m), data_len);
> +
> +		src = rte_pktmbuf_mtod(m, uint8_t *);
> +		memcpy(dst, src, seg_len);
> +		m = m->next;
> +		data_len -= seg_len;
> +		dst += seg_len;
> +	}
> +
> +	if (data_len) {
> +		RTE_LOG(ERR, USER1, "Error -1: write back data\n");
> +		return -1;
> +	}
> +
> +	if (env.digest)
> +		memcpy(dst, env.digest, env.digest_len);
> +
> +	val->val = wb_data;
> +	val->len = total_len;
> +
> +	return 0;
>   }
>   
>   static int
> @@ -1015,7 +1142,7 @@ fips_run_test(void)
>   static int
>   fips_generic_test(void)
>   {
> -	struct fips_val val;
> +	struct fips_val val = {NULL, 0};
>   	int ret;
>   
>   	fips_test_write_one_case();
> @@ -1030,7 +1157,9 @@ fips_generic_test(void)
>   		return ret;
>   	}
>   
> -	get_writeback_data(&val);
> +	ret = get_writeback_data(&val);
> +	if (ret < 0)
> +		return ret;
>   
>   	switch (info.file_type) {
>   	case FIPS_TYPE_REQ:
> @@ -1051,6 +1180,7 @@ fips_generic_test(void)
>   	}
>   
>   	fprintf(info.fp_wr, "\n");
> +	free(val.val);
>   
>   	return 0;
>   }
> @@ -1061,7 +1191,7 @@ fips_mct_tdes_test(void)
>   #define TDES_BLOCK_SIZE		8
>   #define TDES_EXTERN_ITER	400
>   #define TDES_INTERN_ITER	10000
> -	struct fips_val val, val_key;
> +	struct fips_val val = {NULL, 0}, val_key;
>   	uint8_t prev_out[TDES_BLOCK_SIZE] = {0};
>   	uint8_t prev_prev_out[TDES_BLOCK_SIZE] = {0};
>   	uint8_t prev_in[TDES_BLOCK_SIZE] = {0};
> @@ -1088,7 +1218,9 @@ fips_mct_tdes_test(void)
>   				return ret;
>   			}
>   
> -			get_writeback_data(&val);
> +			ret = get_writeback_data(&val);
> +			if (ret < 0)
> +				return ret;
>   
>   			if (info.op == FIPS_TEST_DEC_AUTH_VERIF)
>   				memcpy(prev_in, vec.ct.val, TDES_BLOCK_SIZE);
> @@ -1215,6 +1347,9 @@ fips_mct_tdes_test(void)
>   		}
>   	}
>   
> +	if (val.val)
> +		free(val.val);
> +
>   	return 0;
>   }
>   
> @@ -1224,7 +1359,7 @@ fips_mct_aes_ecb_test(void)
>   #define AES_BLOCK_SIZE	16
>   #define AES_EXTERN_ITER	100
>   #define AES_INTERN_ITER	1000
> -	struct fips_val val, val_key;
> +	struct fips_val val = {NULL, 0}, val_key;
>   	uint8_t prev_out[AES_BLOCK_SIZE] = {0};
>   	uint32_t i, j, k;
>   	int ret;
> @@ -1246,7 +1381,9 @@ fips_mct_aes_ecb_test(void)
>   				return ret;
>   			}
>   
> -			get_writeback_data(&val);
> +			ret = get_writeback_data(&val);
> +			if (ret < 0)
> +				return ret;
>   
>   			if (info.op == FIPS_TEST_ENC_AUTH_GEN)
>   				memcpy(vec.pt.val, val.val, AES_BLOCK_SIZE);
> @@ -1290,6 +1427,9 @@ fips_mct_aes_ecb_test(void)
>   		}
>   	}
>   
> +	if (val.val)
> +		free(val.val);
> +
>   	return 0;
>   }
>   static int
> @@ -1298,7 +1438,7 @@ fips_mct_aes_test(void)
>   #define AES_BLOCK_SIZE	16
>   #define AES_EXTERN_ITER	100
>   #define AES_INTERN_ITER	1000
> -	struct fips_val val, val_key;
> +	struct fips_val val = {NULL, 0}, val_key;
>   	uint8_t prev_out[AES_BLOCK_SIZE] = {0};
>   	uint8_t prev_in[AES_BLOCK_SIZE] = {0};
>   	uint32_t i, j, k;
> @@ -1394,6 +1534,9 @@ fips_mct_aes_test(void)
>   			memcpy(vec.iv.val, val.val, AES_BLOCK_SIZE);
>   	}
>   
> +	if (val.val)
> +		free(val.val);
> +
>   	return 0;
>   }
>   
> @@ -1403,7 +1546,7 @@ fips_mct_sha_test(void)
>   #define SHA_EXTERN_ITER	100
>   #define SHA_INTERN_ITER	1000
>   #define SHA_MD_BLOCK	3
> -	struct fips_val val, md[SHA_MD_BLOCK];
> +	struct fips_val val = {NULL, 0}, md[SHA_MD_BLOCK];
>   	char temp[MAX_DIGEST_SIZE*2];
>   	int ret;
>   	uint32_t i, j;
> @@ -1477,6 +1620,9 @@ fips_mct_sha_test(void)
>   
>   	rte_free(vec.pt.val);
>   
> +	if (val.val)
> +		free(val.val);
> +
>   	return 0;
>   }
>   
> @@ -1568,7 +1714,6 @@ fips_test_one_file(void)
>   {
>   	int fetch_ret = 0, ret;
>   
> -
>   	ret = init_test_ops();
>   	if (ret < 0) {
>   		RTE_LOG(ERR, USER1, "Error %i: Init test op\n", ret);
> @@ -1616,6 +1761,10 @@ fips_test_one_file(void)
>   
>   	fips_test_clear();
>   
> -	return ret;
> +	if (env.digest)
> +		rte_free(env.digest);
> +	if (env.mbuf)
> +		rte_pktmbuf_free(env.mbuf);
>   
> +	return ret;
>   }
  
Fan Zhang Sept. 8, 2020, 10:13 a.m. UTC | #2
Hi Suanming Mou,

Thanks for the review.

> -----Original Message-----
> From: Suanming Mou <suanmingm@nvidia.com>
> Sent: Monday, September 7, 2020 2:32 PM
> To: Zhang, Roy Fan <roy.fan.zhang@intel.com>; dev@dpdk.org
> Cc: akhil.goyal@nxp.com; Trahe, Fiona <fiona.trahe@intel.com>; Kusztal,
> ArkadiuszX <arkadiuszx.kusztal@intel.com>; Dybkowski, AdamX
> <adamx.dybkowski@intel.com>
> Subject: Re: [dpdk-dev] [dpdk-dev v2 1/2] fips_validation: add SGL support
> 
> Hi,
> 
...
> > @@ -50,8 +55,10 @@ cryptodev_fips_validate_app_int(void)
> >   {
> >   	struct rte_cryptodev_config conf = {rte_socket_id(), 1, 0};
> >   	struct rte_cryptodev_qp_conf qp_conf = {128, NULL, NULL};
> > +	struct rte_cryptodev_info dev_info;
> Better to initialize the dev_info here?

[Fan] dev_info is initialized by rte_cryptodev_info_get() after the device is
successfully configured. So at least we can be sure the device ID is a valid
one and the buffer will be properly set by the driver. Plus the
the implementation of rte_cryptodev_info_get() will do a memset to
the dev_info buffer so it is not necessary to be initialized there.

> >   	uint32_t sess_sz = rte_cryptodev_sym_get_private_session_size(
> >   			env.dev_id);
> > +	uint32_t nb_mbufs = UINT16_MAX / env.mbuf_data_room + 1;
> >   	int ret;
> >

Regards,
Fan
  
Griffin, John Sept. 17, 2020, 9:20 a.m. UTC | #3
> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Fan Zhang
> Sent: Friday, September 4, 2020 5:10 PM
> To: dev@dpdk.org
> Cc: akhil.goyal@nxp.com; Trahe, Fiona <fiona.trahe@intel.com>; Kusztal,
> ArkadiuszX <arkadiuszx.kusztal@intel.com>; Dybkowski, AdamX
> <adamx.dybkowski@intel.com>; Zhang, Roy Fan <roy.fan.zhang@intel.com>
> Subject: [dpdk-dev] [dpdk-dev v2 1/2] fips_validation: add SGL support
> 
> This patch adds SGL support to FIPS sample application.
> Originally the application allocates single mbuf of 64KB - 1 bytes data room.
> With the change the user may reduce the mbuf dataroom size by using the
> add cmdline option. If the input test data is longer than the user provided
> data room size the application will automatically build chained mbufs for the
> target cryptodev PMD to test.
> 
> Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
> ---
>  doc/guides/sample_app_ug/fips_validation.rst |   6 +
>  examples/fips_validation/fips_validation.h   |   3 +-
>  examples/fips_validation/main.c              | 377 +++++++++++++------
>  3 files changed, 271 insertions(+), 115 deletions(-)
> 
> --
> 2.20.1

Acked-by: John Griffin <john.griffin@intel.com>
  

Patch

diff --git a/doc/guides/sample_app_ug/fips_validation.rst b/doc/guides/sample_app_ug/fips_validation.rst
index 2953fddeb..8d3db2214 100644
--- a/doc/guides/sample_app_ug/fips_validation.rst
+++ b/doc/guides/sample_app_ug/fips_validation.rst
@@ -96,6 +96,7 @@  The application requires a number of command line options:
          -- --req-file FILE_PATH/FOLDER_PATH
          --rsp-file FILE_PATH/FOLDER_PATH
          [--cryptodev DEVICE_NAME] [--cryptodev-id ID] [--path-is-folder]
+         --mbuf-dataroom DATAROOM_SIZE
 
 where,
   * req-file: The path of the request file or folder, separated by
@@ -111,6 +112,11 @@  where,
   * path-is-folder: If presented the application expects req-file and rsp-file
     are folder paths.
 
+  * mbuf-dataroom: By default the application creates mbuf pool with maximum
+    possible data room (65535 bytes). If the user wants to test scatter-gather
+    list feature of the PMD he or she may set this value to reduce the dataroom
+    size so that the input data may be dividied into multiple chained mbufs.
+
 
 To run the application in linux environment to test one AES FIPS test data
 file for crypto_aesni_mb PMD, issue the command:
diff --git a/examples/fips_validation/fips_validation.h b/examples/fips_validation/fips_validation.h
index 75fa555fa..ecf3d54dd 100644
--- a/examples/fips_validation/fips_validation.h
+++ b/examples/fips_validation/fips_validation.h
@@ -12,7 +12,8 @@ 
 #define MAX_CASE_LINE		15
 #define MAX_LINE_CHAR		204800 /*< max number of characters per line */
 #define MAX_NB_TESTS		10240
-#define MAX_BUF_SIZE		2048
+#define DEF_MBUF_SEG_SIZE	(UINT16_MAX - sizeof(struct rte_mbuf) - \
+				RTE_PKTMBUF_HEADROOM)
 #define MAX_STRING_SIZE		64
 #define MAX_DIGEST_SIZE		64
 
diff --git a/examples/fips_validation/main.c b/examples/fips_validation/main.c
index efd32a86a..fadca6e0c 100644
--- a/examples/fips_validation/main.c
+++ b/examples/fips_validation/main.c
@@ -17,6 +17,7 @@ 
 
 #define REQ_FILE_PATH_KEYWORD	"req-file"
 #define RSP_FILE_PATH_KEYWORD	"rsp-file"
+#define MBUF_DATAROOM_KEYWORD	"mbuf-dataroom"
 #define FOLDER_KEYWORD		"path-is-folder"
 #define CRYPTODEV_KEYWORD	"cryptodev"
 #define CRYPTODEV_ID_KEYWORD	"cryptodev-id"
@@ -33,15 +34,19 @@  struct cryptodev_fips_validate_env {
 	const char *req_path;
 	const char *rsp_path;
 	uint32_t is_path_folder;
-	uint32_t dev_id;
+	uint8_t dev_id;
+	uint8_t dev_support_sgl;
+	uint16_t mbuf_data_room;
 	struct rte_mempool *mpool;
 	struct rte_mempool *sess_mpool;
 	struct rte_mempool *sess_priv_mpool;
 	struct rte_mempool *op_pool;
 	struct rte_mbuf *mbuf;
+	uint8_t *digest;
+	uint16_t digest_len;
 	struct rte_crypto_op *op;
 	struct rte_cryptodev_sym_session *sess;
-	uint32_t self_test;
+	uint16_t self_test;
 	struct fips_dev_broken_test_config *broken_test_config;
 } env;
 
@@ -50,8 +55,10 @@  cryptodev_fips_validate_app_int(void)
 {
 	struct rte_cryptodev_config conf = {rte_socket_id(), 1, 0};
 	struct rte_cryptodev_qp_conf qp_conf = {128, NULL, NULL};
+	struct rte_cryptodev_info dev_info;
 	uint32_t sess_sz = rte_cryptodev_sym_get_private_session_size(
 			env.dev_id);
+	uint32_t nb_mbufs = UINT16_MAX / env.mbuf_data_room + 1;
 	int ret;
 
 	if (env.self_test) {
@@ -70,8 +77,15 @@  cryptodev_fips_validate_app_int(void)
 	if (ret < 0)
 		return ret;
 
-	env.mpool = rte_pktmbuf_pool_create("FIPS_MEMPOOL", 128, 0, 0,
-			UINT16_MAX, rte_socket_id());
+	rte_cryptodev_info_get(env.dev_id, &dev_info);
+	if (dev_info.feature_flags & RTE_CRYPTODEV_FF_IN_PLACE_SGL)
+		env.dev_support_sgl = 1;
+	else
+		env.dev_support_sgl = 0;
+
+	env.mpool = rte_pktmbuf_pool_create("FIPS_MEMPOOL", nb_mbufs,
+			0, 0, sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM +
+			env.mbuf_data_room, rte_socket_id());
 	if (!env.mpool)
 		return ret;
 
@@ -102,10 +116,6 @@  cryptodev_fips_validate_app_int(void)
 	if (!env.op_pool)
 		goto error_exit;
 
-	env.mbuf = rte_pktmbuf_alloc(env.mpool);
-	if (!env.mbuf)
-		goto error_exit;
-
 	env.op = rte_crypto_op_alloc(env.op_pool, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
 	if (!env.op)
 		goto error_exit;
@@ -160,7 +170,7 @@  parse_cryptodev_arg(char *arg)
 		return id;
 	}
 
-	env.dev_id = (uint32_t)id;
+	env.dev_id = (uint8_t)id;
 
 	return 0;
 }
@@ -191,19 +201,21 @@  parse_cryptodev_id_arg(char *arg)
 static void
 cryptodev_fips_validate_usage(const char *prgname)
 {
+	uint32_t def_mbuf_seg_size = DEF_MBUF_SEG_SIZE;
 	printf("%s [EAL options] --\n"
 		"  --%s: REQUEST-FILE-PATH\n"
 		"  --%s: RESPONSE-FILE-PATH\n"
 		"  --%s: indicating both paths are folders\n"
+		"  --%s: mbuf dataroom size (default %u bytes)\n"
 		"  --%s: CRYPTODEV-NAME\n"
 		"  --%s: CRYPTODEV-ID-NAME\n"
 		"  --%s: self test indicator\n"
 		"  --%s: self broken test ID\n"
 		"  --%s: self broken test direction\n",
 		prgname, REQ_FILE_PATH_KEYWORD, RSP_FILE_PATH_KEYWORD,
-		FOLDER_KEYWORD, CRYPTODEV_KEYWORD, CRYPTODEV_ID_KEYWORD,
-		CRYPTODEV_ST_KEYWORD, CRYPTODEV_BK_ID_KEYWORD,
-		CRYPTODEV_BK_DIR_KEY);
+		FOLDER_KEYWORD, MBUF_DATAROOM_KEYWORD, def_mbuf_seg_size,
+		CRYPTODEV_KEYWORD, CRYPTODEV_ID_KEYWORD, CRYPTODEV_ST_KEYWORD,
+		CRYPTODEV_BK_ID_KEYWORD, CRYPTODEV_BK_DIR_KEY);
 }
 
 static int
@@ -217,6 +229,7 @@  cryptodev_fips_validate_parse_args(int argc, char **argv)
 			{REQ_FILE_PATH_KEYWORD, required_argument, 0, 0},
 			{RSP_FILE_PATH_KEYWORD, required_argument, 0, 0},
 			{FOLDER_KEYWORD, no_argument, 0, 0},
+			{MBUF_DATAROOM_KEYWORD, required_argument, 0, 0},
 			{CRYPTODEV_KEYWORD, required_argument, 0, 0},
 			{CRYPTODEV_ID_KEYWORD, required_argument, 0, 0},
 			{CRYPTODEV_ST_KEYWORD, no_argument, 0, 0},
@@ -227,6 +240,14 @@  cryptodev_fips_validate_parse_args(int argc, char **argv)
 
 	argvopt = argv;
 
+	env.mbuf_data_room = DEF_MBUF_SEG_SIZE;
+	if (rte_cryptodev_count())
+		env.dev_id = 0;
+	else {
+		cryptodev_fips_validate_usage(prgname);
+		return -EINVAL;
+	}
+
 	while ((opt = getopt_long(argc, argvopt, "s:",
 				  lgopts, &option_index)) != EOF) {
 
@@ -305,6 +326,23 @@  cryptodev_fips_validate_parse_args(int argc, char **argv)
 					cryptodev_fips_validate_usage(prgname);
 					return -EINVAL;
 				}
+			} else if (strcmp(lgopts[option_index].name,
+					MBUF_DATAROOM_KEYWORD) == 0) {
+				uint32_t data_room_size;
+
+				if (parser_read_uint32(&data_room_size,
+						optarg) < 0) {
+					cryptodev_fips_validate_usage(prgname);
+					return -EINVAL;
+				}
+
+				if (data_room_size == 0 ||
+						data_room_size > UINT16_MAX) {
+					cryptodev_fips_validate_usage(prgname);
+					return -EINVAL;
+				}
+
+				env.mbuf_data_room = data_room_size;
 			} else {
 				cryptodev_fips_validate_usage(prgname);
 				return -EINVAL;
@@ -315,8 +353,7 @@  cryptodev_fips_validate_parse_args(int argc, char **argv)
 		}
 	}
 
-	if (env.req_path == NULL || env.rsp_path == NULL ||
-			env.dev_id == UINT32_MAX) {
+	if (env.req_path == NULL || env.rsp_path == NULL) {
 		cryptodev_fips_validate_usage(prgname);
 		return -EINVAL;
 	}
@@ -451,60 +488,124 @@  struct fips_test_ops {
 } test_ops;
 
 static int
-prepare_cipher_op(void)
+prepare_data_mbufs(struct fips_val *val)
 {
-	struct rte_crypto_sym_op *sym = env.op->sym;
-	uint8_t *iv = rte_crypto_op_ctod_offset(env.op, uint8_t *, IV_OFF);
+	struct rte_mbuf *m, *head = 0;
+	uint8_t *src = val->val;
+	uint32_t total_len = val->len;
+	uint16_t nb_seg;
+	int ret = 0;
 
-	__rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
-	rte_pktmbuf_reset(env.mbuf);
-
-	sym->m_src = env.mbuf;
-	sym->cipher.data.offset = 0;
+	if (env.mbuf)
+		rte_pktmbuf_free(env.mbuf);
 
-	memcpy(iv, vec.iv.val, vec.iv.len);
+	if (total_len > RTE_MBUF_MAX_NB_SEGS) {
+		RTE_LOG(ERR, USER1, "Data len %u too big\n", total_len);
+		return -EPERM;
+	}
 
-	if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
-		uint8_t *pt;
+	nb_seg = total_len / env.mbuf_data_room;
+	if (total_len % env.mbuf_data_room)
+		nb_seg++;
 
-		if (vec.pt.len > RTE_MBUF_MAX_NB_SEGS) {
-			RTE_LOG(ERR, USER1, "PT len %u\n", vec.pt.len);
-			return -EPERM;
-		}
+	m = rte_pktmbuf_alloc(env.mpool);
+	if (!m) {
+		RTE_LOG(ERR, USER1, "Error %i: Not enough mbuf\n",
+				-ENOMEM);
+		return -ENOMEM;
+	}
+	head = m;
 
-		pt = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.pt.len);
+	while (nb_seg) {
+		uint16_t len = RTE_MIN(total_len, env.mbuf_data_room);
+		uint8_t *dst = (uint8_t *)rte_pktmbuf_append(m, len);
 
-		if (!pt) {
+		if (!dst) {
 			RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
 					-ENOMEM);
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto error_exit;
 		}
 
-		memcpy(pt, vec.pt.val, vec.pt.len);
-		sym->cipher.data.length = vec.pt.len;
+		memcpy(dst, src, len);
 
-	} else {
-		uint8_t *ct;
-
-		if (vec.ct.len > RTE_MBUF_MAX_NB_SEGS) {
-			RTE_LOG(ERR, USER1, "CT len %u\n", vec.ct.len);
-			return -EPERM;
+		if (head != m) {
+			ret = rte_pktmbuf_chain(head, m);
+			if (ret) {
+				rte_pktmbuf_free(m);
+				RTE_LOG(ERR, USER1, "Error %i: SGL build\n",
+						ret);
+				goto error_exit;
+			}
 		}
+		total_len -= len;
 
-		ct = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.ct.len);
+		if (total_len) {
+			if (!env.dev_support_sgl) {
+				RTE_LOG(ERR, USER1, "SGL not supported\n");
+				ret = -EPERM;
+				goto error_exit;
+			}
 
-		if (!ct) {
-			RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
-					-ENOMEM);
-			return -ENOMEM;
-		}
+			m = rte_pktmbuf_alloc(env.mpool);
+			if (!m) {
+				RTE_LOG(ERR, USER1, "Error %i: No memory\n",
+						-ENOMEM);
+				goto error_exit;
+			}
+		} else
+			break;
+
+		src += len;
+		nb_seg--;
+	}
+
+	if (total_len) {
+		RTE_LOG(ERR, USER1, "Error %i: Failed to store all data\n",
+				-ENOMEM);
+		goto error_exit;
+	}
+
+	env.mbuf = head;
+
+	return 0;
+
+error_exit:
+	if (head)
+		rte_pktmbuf_free(head);
+	return ret;
+}
+
+static int
+prepare_cipher_op(void)
+{
+	struct rte_crypto_sym_op *sym = env.op->sym;
+	uint8_t *iv = rte_crypto_op_ctod_offset(env.op, uint8_t *, IV_OFF);
+	int ret;
+
+	__rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
+
+	memcpy(iv, vec.iv.val, vec.iv.len);
+
+	if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
+		ret = prepare_data_mbufs(&vec.pt);
+		if (ret < 0)
+			return ret;
+
+		sym->cipher.data.length = vec.pt.len;
+	} else {
+		ret = prepare_data_mbufs(&vec.ct);
+		if (ret < 0)
+			return ret;
 
-		memcpy(ct, vec.ct.val, vec.ct.len);
 		sym->cipher.data.length = vec.ct.len;
 	}
 
 	rte_crypto_op_attach_sym_session(env.op, env.sess);
 
+	sym->m_src = env.mbuf;
+	sym->cipher.data.offset = 0;
+
 	return 0;
 }
 
@@ -512,32 +613,33 @@  static int
 prepare_auth_op(void)
 {
 	struct rte_crypto_sym_op *sym = env.op->sym;
-	uint8_t *pt;
+	int ret;
 
 	__rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
-	rte_pktmbuf_reset(env.mbuf);
 
-	sym->m_src = env.mbuf;
-	sym->auth.data.offset = 0;
+	ret = prepare_data_mbufs(&vec.pt);
+	if (ret < 0)
+		return ret;
 
-	pt = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.pt.len +
-			vec.cipher_auth.digest.len);
+	if (env.digest)
+		rte_free(env.digest);
 
-	if (!pt) {
-		RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
-				-ENOMEM);
+	env.digest = rte_zmalloc(NULL, vec.cipher_auth.digest.len,
+			RTE_CACHE_LINE_SIZE);
+	if (!env.digest) {
+		RTE_LOG(ERR, USER1, "Not enough memory\n");
 		return -ENOMEM;
 	}
+	env.digest_len = vec.cipher_auth.digest.len;
 
+	sym->m_src = env.mbuf;
+	sym->auth.data.offset = 0;
 	sym->auth.data.length = vec.pt.len;
-	sym->auth.digest.data = pt + vec.pt.len;
-	sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
-			env.mbuf, vec.pt.len);
-
-	memcpy(pt, vec.pt.val, vec.pt.len);
+	sym->auth.digest.data = env.digest;
+	sym->auth.digest.phys_addr = rte_malloc_virt2iova(env.digest);
 
 	if (info.op == FIPS_TEST_DEC_AUTH_VERIF)
-		memcpy(pt + vec.pt.len, vec.cipher_auth.digest.val,
+		memcpy(env.digest, vec.cipher_auth.digest.val,
 				vec.cipher_auth.digest.len);
 
 	rte_crypto_op_attach_sym_session(env.op, env.sess);
@@ -550,65 +652,53 @@  prepare_aead_op(void)
 {
 	struct rte_crypto_sym_op *sym = env.op->sym;
 	uint8_t *iv = rte_crypto_op_ctod_offset(env.op, uint8_t *, IV_OFF);
+	int ret;
 
 	__rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
-	rte_pktmbuf_reset(env.mbuf);
 
 	if (info.algo == FIPS_TEST_ALGO_AES_CCM)
-		memcpy(iv + 1, vec.iv.val, vec.iv.len);
-	else
-		memcpy(iv, vec.iv.val, vec.iv.len);
+		iv++;
 
-	sym->m_src = env.mbuf;
-	sym->aead.data.offset = 0;
-	sym->aead.aad.data = vec.aead.aad.val;
-	sym->aead.aad.phys_addr = rte_malloc_virt2iova(sym->aead.aad.data);
+	if (vec.iv.val)
+		memcpy(iv, vec.iv.val, vec.iv.len);
+	else
+		/* if REQ file has iv length but not data, default as all 0 */
+		memset(iv, 0, vec.iv.len);
 
 	if (info.op == FIPS_TEST_ENC_AUTH_GEN) {
-		uint8_t *pt;
-
-		if (vec.pt.len > RTE_MBUF_MAX_NB_SEGS) {
-			RTE_LOG(ERR, USER1, "PT len %u\n", vec.pt.len);
-			return -EPERM;
-		}
-
-		pt = (uint8_t *)rte_pktmbuf_append(env.mbuf,
-				vec.pt.len + vec.aead.digest.len);
+		ret = prepare_data_mbufs(&vec.pt);
+		if (ret < 0)
+			return ret;
 
-		if (!pt) {
-			RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
-					-ENOMEM);
+		if (env.digest)
+			rte_free(env.digest);
+		env.digest = rte_zmalloc(NULL, vec.aead.digest.len,
+				RTE_CACHE_LINE_SIZE);
+		if (!env.digest) {
+			RTE_LOG(ERR, USER1, "Not enough memory\n");
 			return -ENOMEM;
 		}
+		env.digest_len = vec.cipher_auth.digest.len;
 
-		memcpy(pt, vec.pt.val, vec.pt.len);
 		sym->aead.data.length = vec.pt.len;
-		sym->aead.digest.data = pt + vec.pt.len;
-		sym->aead.digest.phys_addr = rte_pktmbuf_mtophys_offset(
-				env.mbuf, vec.pt.len);
+		sym->aead.digest.data = env.digest;
+		sym->aead.digest.phys_addr = rte_malloc_virt2iova(env.digest);
 	} else {
-		uint8_t *ct;
-
-		if (vec.ct.len > RTE_MBUF_MAX_NB_SEGS) {
-			RTE_LOG(ERR, USER1, "CT len %u\n", vec.ct.len);
-			return -EPERM;
-		}
-
-		ct = (uint8_t *)rte_pktmbuf_append(env.mbuf, vec.ct.len);
-
-		if (!ct) {
-			RTE_LOG(ERR, USER1, "Error %i: MBUF too small\n",
-					-ENOMEM);
-			return -ENOMEM;
-		}
+		ret = prepare_data_mbufs(&vec.ct);
+		if (ret < 0)
+			return ret;
 
-		memcpy(ct, vec.ct.val, vec.ct.len);
 		sym->aead.data.length = vec.ct.len;
 		sym->aead.digest.data = vec.aead.digest.val;
 		sym->aead.digest.phys_addr = rte_malloc_virt2iova(
 				sym->aead.digest.data);
 	}
 
+	sym->m_src = env.mbuf;
+	sym->aead.data.offset = 0;
+	sym->aead.aad.data = vec.aead.aad.val;
+	sym->aead.aad.phys_addr = rte_malloc_virt2iova(sym->aead.aad.data);
+
 	rte_crypto_op_attach_sym_session(env.op, env.sess);
 
 	return 0;
@@ -952,11 +1042,48 @@  prepare_xts_xform(struct rte_crypto_sym_xform *xform)
 	return 0;
 }
 
-static void
+static int
 get_writeback_data(struct fips_val *val)
 {
-	val->val = rte_pktmbuf_mtod(env.mbuf, uint8_t *);
-	val->len = rte_pktmbuf_pkt_len(env.mbuf);
+	struct rte_mbuf *m = env.mbuf;
+	uint16_t data_len = rte_pktmbuf_pkt_len(m);
+	uint16_t total_len = data_len + env.digest_len;
+	uint8_t *src, *dst, *wb_data;
+
+	/* in case val is reused for MCT test, try to free the buffer first */
+	if (val->val) {
+		free(val->val);
+		val->val = NULL;
+	}
+
+	wb_data = dst = calloc(1, total_len);
+	if (!dst) {
+		RTE_LOG(ERR, USER1, "Error %i: Not enough memory\n", -ENOMEM);
+		return -ENOMEM;
+	}
+
+	while (m && data_len) {
+		uint16_t seg_len = RTE_MIN(rte_pktmbuf_data_len(m), data_len);
+
+		src = rte_pktmbuf_mtod(m, uint8_t *);
+		memcpy(dst, src, seg_len);
+		m = m->next;
+		data_len -= seg_len;
+		dst += seg_len;
+	}
+
+	if (data_len) {
+		RTE_LOG(ERR, USER1, "Error -1: write back data\n");
+		return -1;
+	}
+
+	if (env.digest)
+		memcpy(dst, env.digest, env.digest_len);
+
+	val->val = wb_data;
+	val->len = total_len;
+
+	return 0;
 }
 
 static int
@@ -1015,7 +1142,7 @@  fips_run_test(void)
 static int
 fips_generic_test(void)
 {
-	struct fips_val val;
+	struct fips_val val = {NULL, 0};
 	int ret;
 
 	fips_test_write_one_case();
@@ -1030,7 +1157,9 @@  fips_generic_test(void)
 		return ret;
 	}
 
-	get_writeback_data(&val);
+	ret = get_writeback_data(&val);
+	if (ret < 0)
+		return ret;
 
 	switch (info.file_type) {
 	case FIPS_TYPE_REQ:
@@ -1051,6 +1180,7 @@  fips_generic_test(void)
 	}
 
 	fprintf(info.fp_wr, "\n");
+	free(val.val);
 
 	return 0;
 }
@@ -1061,7 +1191,7 @@  fips_mct_tdes_test(void)
 #define TDES_BLOCK_SIZE		8
 #define TDES_EXTERN_ITER	400
 #define TDES_INTERN_ITER	10000
-	struct fips_val val, val_key;
+	struct fips_val val = {NULL, 0}, val_key;
 	uint8_t prev_out[TDES_BLOCK_SIZE] = {0};
 	uint8_t prev_prev_out[TDES_BLOCK_SIZE] = {0};
 	uint8_t prev_in[TDES_BLOCK_SIZE] = {0};
@@ -1088,7 +1218,9 @@  fips_mct_tdes_test(void)
 				return ret;
 			}
 
-			get_writeback_data(&val);
+			ret = get_writeback_data(&val);
+			if (ret < 0)
+				return ret;
 
 			if (info.op == FIPS_TEST_DEC_AUTH_VERIF)
 				memcpy(prev_in, vec.ct.val, TDES_BLOCK_SIZE);
@@ -1215,6 +1347,9 @@  fips_mct_tdes_test(void)
 		}
 	}
 
+	if (val.val)
+		free(val.val);
+
 	return 0;
 }
 
@@ -1224,7 +1359,7 @@  fips_mct_aes_ecb_test(void)
 #define AES_BLOCK_SIZE	16
 #define AES_EXTERN_ITER	100
 #define AES_INTERN_ITER	1000
-	struct fips_val val, val_key;
+	struct fips_val val = {NULL, 0}, val_key;
 	uint8_t prev_out[AES_BLOCK_SIZE] = {0};
 	uint32_t i, j, k;
 	int ret;
@@ -1246,7 +1381,9 @@  fips_mct_aes_ecb_test(void)
 				return ret;
 			}
 
-			get_writeback_data(&val);
+			ret = get_writeback_data(&val);
+			if (ret < 0)
+				return ret;
 
 			if (info.op == FIPS_TEST_ENC_AUTH_GEN)
 				memcpy(vec.pt.val, val.val, AES_BLOCK_SIZE);
@@ -1290,6 +1427,9 @@  fips_mct_aes_ecb_test(void)
 		}
 	}
 
+	if (val.val)
+		free(val.val);
+
 	return 0;
 }
 static int
@@ -1298,7 +1438,7 @@  fips_mct_aes_test(void)
 #define AES_BLOCK_SIZE	16
 #define AES_EXTERN_ITER	100
 #define AES_INTERN_ITER	1000
-	struct fips_val val, val_key;
+	struct fips_val val = {NULL, 0}, val_key;
 	uint8_t prev_out[AES_BLOCK_SIZE] = {0};
 	uint8_t prev_in[AES_BLOCK_SIZE] = {0};
 	uint32_t i, j, k;
@@ -1394,6 +1534,9 @@  fips_mct_aes_test(void)
 			memcpy(vec.iv.val, val.val, AES_BLOCK_SIZE);
 	}
 
+	if (val.val)
+		free(val.val);
+
 	return 0;
 }
 
@@ -1403,7 +1546,7 @@  fips_mct_sha_test(void)
 #define SHA_EXTERN_ITER	100
 #define SHA_INTERN_ITER	1000
 #define SHA_MD_BLOCK	3
-	struct fips_val val, md[SHA_MD_BLOCK];
+	struct fips_val val = {NULL, 0}, md[SHA_MD_BLOCK];
 	char temp[MAX_DIGEST_SIZE*2];
 	int ret;
 	uint32_t i, j;
@@ -1477,6 +1620,9 @@  fips_mct_sha_test(void)
 
 	rte_free(vec.pt.val);
 
+	if (val.val)
+		free(val.val);
+
 	return 0;
 }
 
@@ -1568,7 +1714,6 @@  fips_test_one_file(void)
 {
 	int fetch_ret = 0, ret;
 
-
 	ret = init_test_ops();
 	if (ret < 0) {
 		RTE_LOG(ERR, USER1, "Error %i: Init test op\n", ret);
@@ -1616,6 +1761,10 @@  fips_test_one_file(void)
 
 	fips_test_clear();
 
-	return ret;
+	if (env.digest)
+		rte_free(env.digest);
+	if (env.mbuf)
+		rte_pktmbuf_free(env.mbuf);
 
+	return ret;
 }