DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v6 01/17] net/i40e: store ethertype filter
From: Ferruh Yigit @ 2017-01-05 17:46 UTC (permalink / raw)
  To: Beilei Xing, jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-2-git-send-email-beilei.xing@intel.com>

On 1/5/2017 3:45 PM, Beilei Xing wrote:
> Currently there's no ethertype filter stored in SW.
> This patch stores ethertype filter with cuckoo hash
> in SW, also adds protection if an ethertype filter
> has been added.
> 
> Signed-off-by: Beilei Xing <beilei.xing@intel.com>
> ---

<...>

> @@ -939,9 +946,18 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
>  	int ret;
>  	uint32_t len;
>  	uint8_t aq_fail = 0;
> +	struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
>  
>  	PMD_INIT_FUNC_TRACE();
>  
> +	char ethertype_hash_name[RTE_HASH_NAMESIZE];
> +	struct rte_hash_parameters ethertype_hash_params = {
> +		.name = ethertype_hash_name,
> +		.entries = I40E_MAX_ETHERTYPE_FILTER_NUM,
> +		.key_len = sizeof(struct i40e_ethertype_filter_input),
> +		.hash_func = rte_hash_crc,
> +	};
> +
>  	dev->dev_ops = &i40e_eth_dev_ops;
>  	dev->rx_pkt_burst = i40e_recv_pkts;
>  	dev->tx_pkt_burst = i40e_xmit_pkts;
> @@ -1182,8 +1198,33 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
>  		pf->flags &= ~I40E_FLAG_DCB;
>  	}
>  
> +	/* Initialize ethertype filter rule list and hash */
> +	TAILQ_INIT(&ethertype_rule->ethertype_list);
> +	snprintf(ethertype_hash_name, RTE_HASH_NAMESIZE,
> +		 "ethertype_%s", dev->data->name);
> +	ethertype_rule->hash_table = rte_hash_create(&ethertype_hash_params);
> +	if (!ethertype_rule->hash_table) {
> +		PMD_INIT_LOG(ERR, "Failed to create ethertype hash table!");
> +		ret = -EINVAL;
> +		goto err_ethertype_hash_table_create;
> +	}
> +	ethertype_rule->hash_map = rte_zmalloc("i40e_ethertype_hash_map",
> +				       sizeof(struct i40e_ethertype_filter *) *
> +				       I40E_MAX_ETHERTYPE_FILTER_NUM,
> +				       0);
> +	if (!ethertype_rule->hash_map) {
> +		PMD_INIT_LOG(ERR,
> +		     "Failed to allocate memory for ethertype hash map!");
> +		ret = -ENOMEM;
> +		goto err_ethertype_hash_map_alloc;
> +	}
> +
>  	return 0;
>  
> +err_ethertype_hash_map_alloc:
> +	rte_hash_free(ethertype_rule->hash_table);
> +err_ethertype_hash_table_create:
> +	rte_free(dev->data->mac_addrs);
>  err_mac_alloc:
>  	i40e_vsi_release(pf->main_vsi);
>  err_setup_pf_switch:

It can be good idea to extract filter related code into a separate
function, eth_i40e_dev_init() is already too big. It is up to you.


> @@ -1206,25 +1247,42 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
>  static int
>  eth_i40e_dev_uninit(struct rte_eth_dev *dev)
>  {
> +	struct i40e_pf *pf;
>  	struct rte_pci_device *pci_dev;
>  	struct rte_intr_handle *intr_handle;
>  	struct i40e_hw *hw;
>  	struct i40e_filter_control_settings settings;
> +	struct i40e_ethertype_filter *p_ethertype;
>  	int ret;
>  	uint8_t aq_fail = 0;
> +	struct i40e_ethertype_rule *ethertype_rule;
>  
>  	PMD_INIT_FUNC_TRACE();
>  
>  	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
>  		return 0;
>  
> +	pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
>  	hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
>  	pci_dev = I40E_DEV_TO_PCI(dev);
>  	intr_handle = &pci_dev->intr_handle;
> +	ethertype_rule = &pf->ethertype;
>  
>  	if (hw->adapter_stopped == 0)
>  		i40e_dev_close(dev);
>  
> +	/* Remove all ethertype director rules and hash */
> +	if (ethertype_rule->hash_map)
> +		rte_free(ethertype_rule->hash_map);
> +	if (ethertype_rule->hash_table)
> +		rte_hash_free(ethertype_rule->hash_table);
> +
> +	while ((p_ethertype = TAILQ_FIRST(&ethertype_rule->ethertype_list))) {
> +		TAILQ_REMOVE(&ethertype_rule->ethertype_list,
> +			     p_ethertype, rules);
> +		rte_free(p_ethertype);
> +	}
> +
>  	dev->dev_ops = NULL;
>  	dev->rx_pkt_burst = NULL;
>  	dev->tx_pkt_burst = NULL;

Same is valid for  eth_i40e_dev_uninit(), if possible having a separate
function for filter related work.

<...>

^ permalink raw reply

* Re: [PATCH v6 00/17] net/i40e: consistent filter API
From: Ferruh Yigit @ 2017-01-05 17:46 UTC (permalink / raw)
  To: Beilei Xing, jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-1-git-send-email-beilei.xing@intel.com>

On 1/5/2017 3:45 PM, Beilei Xing wrote:
> The patch set depends on Adrien's Generic flow API(rte_flow).
> 
> The patches mainly finish following functions:
> 1) Store and restore all kinds of filters.
> 2) Parse all kinds of filters.
> 3) Add flow validate function.
> 4) Add flow create function.
> 5) Add flow destroy function.
> 6) Add flow flush function.
> 
> v6 changes:
>  Change functions' name to be more readable.
>  Add comments for parse_pattern functions to list supported rules.
>  Add comments for parse_action functions to list supported actions.
>  Add ETHTYPE check when parsing ethertype pattern.
> 
> v5 changes:
>  Change some local variable name.
>  Add removing i40e_flow_list during device unint.
>  Fix compile error when gcc compile option isn't '-O0'.
> 
> v4 changes:
>  Change I40E_TCI_MASK with 0xFFFF to align with testpmd.
>  Modidy the stats show when restoring filters.
> 
> v3 changes:
>  Set the related cause pointer to a non-NULL value when error happens.
>  Change return value when error happens.
>  Modify filter_del parameter with key.
>  Malloc filter after checking when delete a filter.
>  Delete meaningless initialization.
>  Add return value when there's error.
>  Change global variable definition.
>  Modify some function declaration.
> 
> v2 changes:
>  Add i40e_flow.c, all flow ops are implemented in the file.
>  Change the whole implementation of all parse flow functions.
>  Update error info for all flow ops.
>  Add flow_list to store flows created.
> 
> Beilei Xing (17):
>   net/i40e: store ethertype filter
>   net/i40e: store tunnel filter
>   net/i40e: store flow director filter
>   net/i40e: restore ethertype filter
>   net/i40e: restore tunnel filter
>   net/i40e: restore flow director filter
>   net/i40e: add flow validate function
>   net/i40e: parse flow director filter
>   net/i40e: parse tunnel filter
>   net/i40e: add flow create function
>   net/i40e: add flow destroy function
>   net/i40e: destroy ethertype filter
>   net/i40e: destroy tunnel filter
>   net/i40e: destroy flow directory filter
>   net/i40e: add flow flush function
>   net/i40e: flush ethertype filters
>   net/i40e: flush tunnel filters
> 

Thanks Beilei,

Overall looks good to me, just two more comments (as reply to relevant
patches).

^ permalink raw reply

* Re: [PATCH] net/mlx5: fix Tx doorbell
From: Ferruh Yigit @ 2017-01-05 17:01 UTC (permalink / raw)
  To: Adrien Mazarguil; +Cc: Nelio Laranjeiro, dev
In-Reply-To: <20170105165223.GQ12822@6wind.com>

On 1/5/2017 4:52 PM, Adrien Mazarguil wrote:
> On Thu, Jan 05, 2017 at 05:32:26PM +0100, Adrien Mazarguil wrote:
>> Hi Ferruh,
>>
>> On Thu, Jan 05, 2017 at 03:19:35PM +0000, Ferruh Yigit wrote:
>>> On 12/9/2016 1:27 PM, Nelio Laranjeiro wrote:
>>>> Too much data is uselessly written to the Tx doorbell.
>>>>
>>>> Fixes: 1d88ba171942 ("net/mlx5: refactor Tx data path")
>>>>
>>>> Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
>>>> Acked-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
>>>>
>>>
>>> Applied to dpdk-next-net/master, thanks.
>>>
>>> Is not CC'ing stable intentional, since this patch depends on a patch
>>> introduced in this release? If not intentional, please CC stable.
>>
>> I intended to update the commit message for this patch as in the meantime we
>> discovered it addresses a significant regression introduced in v16.11.
>>
>> CC'ing stable now.
>>
>> If possible, can you amend the commit log with:
>>
>> ---
>>
>> net/mlx5: fix Tx doorbell
>>
>> Too much data is uselessly written to the Tx doorbell, which since v16.11
>> may also cause Tx queues to behave erratically and crash applications.
>>
>> This regression was seen on VF devices when the BlueFlame buffer size is
>> zero (txq->cqe_n == 0) due to the following change:
>>
>>  -       cqe = &(*txq->cqes)[ci & (txq->cqe_n - 1)].cqe64;
>>  +       cqe = &(*txq->cqes)[ci & ((1 << txq->cqe_n) - 1)];
>>
>> Fixes: 1d88ba171942 ("net/mlx5: refactor Tx data path")
>> Fixes: e2f116ee3cac ("net/mlx5: reduce memory overhead for CQE handling")
>>
>> Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
>> Acked-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
>> Cc: stable@dpdk.org
>>
>> ---
> 
> I mixed the commit that introduced the regression with a similar looking yet
> harmless one, here is the proper message to use, sorry for the noise:
> 
> ---
> 
> net/mlx5: fix Tx doorbell
> 
> Too much data is uselessly written to the Tx doorbell, which since v16.11
> may also cause Tx queues to behave erratically and crash applications.
> 
> This regression was seen on VF devices when the BlueFlame buffer size is
> zero (txq->bf_buf_size) due to the following change:
> 
>  -       txq->bf_offset ^= txq->bf_buf_size;
>  +       txq->bf_offset ^= (1 << txq->bf_buf_size);
> 
> Fixes: 1d88ba171942 ("net/mlx5: refactor Tx data path")
> Fixes: d5793daefec8 ("net/mlx5: reduce memory overhead for BF handling")
> 
> Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
> Acked-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
> Cc: stable@dpdk.org
> 
> ---
> 

Can you please confirm commit in latest next-net?

^ permalink raw reply

* Re: [PATCH] net/mlx5: fix Tx doorbell
From: Adrien Mazarguil @ 2017-01-05 16:52 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: Nelio Laranjeiro, dev, stable
In-Reply-To: <20170105163226.GP12822@6wind.com>

On Thu, Jan 05, 2017 at 05:32:26PM +0100, Adrien Mazarguil wrote:
> Hi Ferruh,
> 
> On Thu, Jan 05, 2017 at 03:19:35PM +0000, Ferruh Yigit wrote:
> > On 12/9/2016 1:27 PM, Nelio Laranjeiro wrote:
> > > Too much data is uselessly written to the Tx doorbell.
> > > 
> > > Fixes: 1d88ba171942 ("net/mlx5: refactor Tx data path")
> > > 
> > > Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
> > > Acked-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
> > > 
> > 
> > Applied to dpdk-next-net/master, thanks.
> > 
> > Is not CC'ing stable intentional, since this patch depends on a patch
> > introduced in this release? If not intentional, please CC stable.
> 
> I intended to update the commit message for this patch as in the meantime we
> discovered it addresses a significant regression introduced in v16.11.
> 
> CC'ing stable now.
> 
> If possible, can you amend the commit log with:
> 
> ---
> 
> net/mlx5: fix Tx doorbell
> 
> Too much data is uselessly written to the Tx doorbell, which since v16.11
> may also cause Tx queues to behave erratically and crash applications.
> 
> This regression was seen on VF devices when the BlueFlame buffer size is
> zero (txq->cqe_n == 0) due to the following change:
> 
>  -       cqe = &(*txq->cqes)[ci & (txq->cqe_n - 1)].cqe64;
>  +       cqe = &(*txq->cqes)[ci & ((1 << txq->cqe_n) - 1)];
> 
> Fixes: 1d88ba171942 ("net/mlx5: refactor Tx data path")
> Fixes: e2f116ee3cac ("net/mlx5: reduce memory overhead for CQE handling")
> 
> Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
> Acked-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
> Cc: stable@dpdk.org
> 
> ---

I mixed the commit that introduced the regression with a similar looking yet
harmless one, here is the proper message to use, sorry for the noise:

---

net/mlx5: fix Tx doorbell

Too much data is uselessly written to the Tx doorbell, which since v16.11
may also cause Tx queues to behave erratically and crash applications.

This regression was seen on VF devices when the BlueFlame buffer size is
zero (txq->bf_buf_size) due to the following change:

 -       txq->bf_offset ^= txq->bf_buf_size;
 +       txq->bf_offset ^= (1 << txq->bf_buf_size);

Fixes: 1d88ba171942 ("net/mlx5: refactor Tx data path")
Fixes: d5793daefec8 ("net/mlx5: reduce memory overhead for BF handling")

Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
Acked-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Cc: stable@dpdk.org

---

-- 
Adrien Mazarguil
6WIND

^ permalink raw reply

* Re: [PATCH v3 1/5] rte_mbuf: add rte_pktmbuf_linearize
From: Kulasek, TomaszX @ 2017-01-05 16:52 UTC (permalink / raw)
  To: De Lara Guarch, Pablo, dev@dpdk.org
In-Reply-To: <E115CCD9D858EF4F90C690B0DCB4D897476BEAED@IRSMSX108.ger.corp.intel.com>

Hi Pablo

> -----Original Message-----
> From: De Lara Guarch, Pablo
> Sent: Thursday, January 5, 2017 16:37
> To: Kulasek, TomaszX <tomaszx.kulasek@intel.com>; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v3 1/5] rte_mbuf: add
> rte_pktmbuf_linearize
> 
> Hi Tomasz,
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tomasz Kulasek
> > Sent: Thursday, January 05, 2017 9:13 AM
> > To: dev@dpdk.org
> > Subject: [dpdk-dev] [PATCH v3 1/5] rte_mbuf: add rte_pktmbuf_linearize
> >
> > This patch adds function rte_pktmbuf_linearize to let crypto PMD
> coalesce
> > chained mbuf before crypto operation and extend their capabilities to
> > support segmented mbufs when device cannot handle them natively.
> >
> > Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
> 
> Could you separate this patch and patch 2/5 out of this patchset and CC
> Olivier,
> the mbuf maintainer, so it can be better reviewed?
> (you can send it as a single patch, both lib and test code)
> Then, send another patchset with the other 3 patches,
> stating that it depends on that patchset.
> 
> Thanks,
> Pablo

Done.

Tomasz

^ permalink raw reply

* [PATCH v4 3/3] test: add sgl unit tests for crypto devices
From: Tomasz Kulasek @ 2017-01-05 16:46 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch, Daniel Mrzyglod
In-Reply-To: <1483634768-35012-1-git-send-email-tomaszx.kulasek@intel.com>

This patch provides unit tests for set of cipher/hash combinations covering
currently implemented crypto PMD's and allowing to verify scatter gather
support.

Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 app/test/test_cryptodev.c                  |  386 ++++++++++++++++++-
 app/test/test_cryptodev.h                  |  139 +++++++
 app/test/test_cryptodev_aes_test_vectors.h |   52 +++
 app/test/test_cryptodev_blockcipher.c      |  180 +++++----
 app/test/test_cryptodev_blockcipher.h      |    1 +
 app/test/test_cryptodev_gcm_test_vectors.h |  553 ++++++++++++++++++++++++++++
 6 files changed, 1241 insertions(+), 70 deletions(-)

diff --git a/app/test/test_cryptodev.c b/app/test/test_cryptodev.c
index 3eaf1b7..4c9a54f 100644
--- a/app/test/test_cryptodev.c
+++ b/app/test/test_cryptodev.c
@@ -1736,6 +1736,10 @@ struct crypto_unittest_params {
 
 	TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, "no room to prepend iv");
 
+	/* For OOP operation both buffers must have the same size */
+	if (ut_params->obuf)
+		rte_pktmbuf_prepend(ut_params->obuf, iv_pad_len);
+
 	memset(sym_op->cipher.iv.data, 0, iv_pad_len);
 	sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf);
 	sym_op->cipher.iv.length = iv_pad_len;
@@ -2557,6 +2561,83 @@ struct crypto_unittest_params {
 }
 
 static int
+test_kasumi_encryption_sgl(const struct kasumi_test_data *tdata)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	struct crypto_unittest_params *ut_params = &unittest_params;
+
+	int retval;
+
+	unsigned int plaintext_pad_len;
+	unsigned int plaintext_len;
+
+	uint8_t buffer[10000];
+	const uint8_t *ciphertext;
+
+	struct rte_cryptodev_info dev_info;
+
+	rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
+	if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) {
+		printf("Device doesn't support scatter-gather. "
+				"Test Skipped.\n");
+		return 0;
+	}
+
+	/* Create KASUMI session */
+	retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0],
+					RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+					RTE_CRYPTO_CIPHER_KASUMI_F8,
+					tdata->key.data, tdata->key.len);
+	if (retval < 0)
+		return retval;
+
+	plaintext_len = ceil_byte_length(tdata->plaintext.len);
+
+
+	/* Append data which is padded to a multiple */
+	/* of the algorithms block size */
+	plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8);
+
+	ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool,
+			plaintext_pad_len, 10);
+
+	pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data);
+
+	/* Create KASUMI operation */
+	retval = create_wireless_algo_cipher_operation(tdata->iv.data,
+					tdata->iv.len,
+					tdata->plaintext.len,
+					tdata->validCipherOffsetLenInBits.len,
+					RTE_CRYPTO_CIPHER_KASUMI_F8);
+	if (retval < 0)
+		return retval;
+
+	ut_params->op = process_crypto_request(ts_params->valid_devs[0],
+						ut_params->op);
+	TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf");
+
+	ut_params->obuf = ut_params->op->sym->m_dst;
+
+	if (ut_params->obuf)
+		ciphertext = rte_pktmbuf_read(ut_params->obuf, tdata->iv.len,
+				plaintext_len, buffer);
+	else
+		ciphertext = rte_pktmbuf_read(ut_params->ibuf, tdata->iv.len,
+				plaintext_len, buffer);
+
+	/* Validate obuf */
+	TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len);
+
+		/* Validate obuf */
+		TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(
+			ciphertext,
+			tdata->ciphertext.data,
+			tdata->validCipherLenInBits.len,
+			"KASUMI Ciphertext data not as expected");
+		return 0;
+}
+
+static int
 test_kasumi_encryption_oop(const struct kasumi_test_data *tdata)
 {
 	struct crypto_testsuite_params *ts_params = &testsuite_params;
@@ -2625,6 +2706,81 @@ struct crypto_unittest_params {
 }
 
 static int
+test_kasumi_encryption_oop_sgl(const struct kasumi_test_data *tdata)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	struct crypto_unittest_params *ut_params = &unittest_params;
+
+	int retval;
+	unsigned int plaintext_pad_len;
+	unsigned int plaintext_len;
+
+	const uint8_t *ciphertext;
+	uint8_t buffer[2048];
+
+	struct rte_cryptodev_info dev_info;
+
+	rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
+	if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) {
+		printf("Device doesn't support scatter-gather. "
+				"Test Skipped.\n");
+		return 0;
+	}
+
+	/* Create KASUMI session */
+	retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0],
+					RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+					RTE_CRYPTO_CIPHER_KASUMI_F8,
+					tdata->key.data, tdata->key.len);
+	if (retval < 0)
+		return retval;
+
+	plaintext_len = ceil_byte_length(tdata->plaintext.len);
+	/* Append data which is padded to a multiple */
+	/* of the algorithms block size */
+	plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8);
+
+	ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool,
+			plaintext_pad_len, 10);
+	ut_params->obuf = create_segmented_mbuf(ts_params->mbuf_pool,
+			plaintext_pad_len, 3);
+
+	/* Append data which is padded to a multiple */
+	/* of the algorithms block size */
+	pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data);
+
+	/* Create KASUMI operation */
+	retval = create_wireless_algo_cipher_operation_oop(tdata->iv.data,
+					tdata->iv.len,
+					tdata->plaintext.len,
+					tdata->validCipherOffsetLenInBits.len,
+					RTE_CRYPTO_CIPHER_KASUMI_F8);
+	if (retval < 0)
+		return retval;
+
+	ut_params->op = process_crypto_request(ts_params->valid_devs[0],
+						ut_params->op);
+	TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf");
+
+	ut_params->obuf = ut_params->op->sym->m_dst;
+	if (ut_params->obuf)
+		ciphertext = rte_pktmbuf_read(ut_params->obuf, tdata->iv.len,
+				plaintext_pad_len, buffer);
+	else
+		ciphertext = rte_pktmbuf_read(ut_params->ibuf, tdata->iv.len,
+				plaintext_pad_len, buffer);
+
+	/* Validate obuf */
+	TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(
+		ciphertext,
+		tdata->ciphertext.data,
+		tdata->validCipherLenInBits.len,
+		"KASUMI Ciphertext data not as expected");
+	return 0;
+}
+
+
+static int
 test_kasumi_decryption_oop(const struct kasumi_test_data *tdata)
 {
 	struct crypto_testsuite_params *ts_params = &testsuite_params;
@@ -2897,6 +3053,85 @@ struct crypto_unittest_params {
 	return 0;
 }
 
+static int
+test_snow3g_encryption_oop_sgl(const struct snow3g_test_data *tdata)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	struct crypto_unittest_params *ut_params = &unittest_params;
+
+	int retval;
+	unsigned int plaintext_pad_len;
+	unsigned int plaintext_len;
+	uint8_t buffer[10000];
+	const uint8_t *ciphertext;
+
+	struct rte_cryptodev_info dev_info;
+
+	rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
+	if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) {
+		printf("Device doesn't support scatter-gather. "
+				"Test Skipped.\n");
+		return 0;
+	}
+
+	/* Create SNOW 3G session */
+	retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0],
+					RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+					RTE_CRYPTO_CIPHER_SNOW3G_UEA2,
+					tdata->key.data, tdata->key.len);
+	if (retval < 0)
+		return retval;
+
+	plaintext_len = ceil_byte_length(tdata->plaintext.len);
+	/* Append data which is padded to a multiple of */
+	/* the algorithms block size */
+	plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16);
+
+	ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool,
+			plaintext_pad_len, 10);
+	ut_params->obuf = create_segmented_mbuf(ts_params->mbuf_pool,
+			plaintext_pad_len, 3);
+
+	TEST_ASSERT_NOT_NULL(ut_params->ibuf,
+			"Failed to allocate input buffer in mempool");
+	TEST_ASSERT_NOT_NULL(ut_params->obuf,
+			"Failed to allocate output buffer in mempool");
+
+	pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data);
+
+	/* Create SNOW 3G operation */
+	retval = create_wireless_algo_cipher_operation_oop(tdata->iv.data,
+					tdata->iv.len,
+					tdata->validCipherLenInBits.len,
+					tdata->validCipherOffsetLenInBits.len,
+					RTE_CRYPTO_CIPHER_SNOW3G_UEA2);
+	if (retval < 0)
+		return retval;
+
+	ut_params->op = process_crypto_request(ts_params->valid_devs[0],
+						ut_params->op);
+	TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf");
+
+	ut_params->obuf = ut_params->op->sym->m_dst;
+	if (ut_params->obuf)
+		ciphertext = rte_pktmbuf_read(ut_params->obuf, tdata->iv.len,
+				plaintext_len, buffer);
+	else
+		ciphertext = rte_pktmbuf_read(ut_params->ibuf, tdata->iv.len,
+				plaintext_len, buffer);
+
+	TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len);
+
+	/* Validate obuf */
+	TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(
+		ciphertext,
+		tdata->ciphertext.data,
+		tdata->validDataLenInBits.len,
+		"SNOW 3G Ciphertext data not as expected");
+
+	return 0;
+}
+
 /* Shift right a buffer by "offset" bits, "offset" < 8 */
 static void
 buffer_shift_right(uint8_t *buffer, uint32_t length, uint8_t offset)
@@ -3552,6 +3787,84 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
 }
 
 static int
+test_zuc_encryption_sgl(const struct zuc_test_data *tdata)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	struct crypto_unittest_params *ut_params = &unittest_params;
+
+	int retval;
+
+	unsigned int plaintext_pad_len;
+	unsigned int plaintext_len;
+	const uint8_t *ciphertext;
+	uint8_t ciphertext_buffer[2048];
+	struct rte_cryptodev_info dev_info;
+
+	rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info);
+	if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) {
+		printf("Device doesn't support scatter-gather. "
+				"Test Skipped.\n");
+		return 0;
+	}
+
+	plaintext_len = ceil_byte_length(tdata->plaintext.len);
+
+	/* Append data which is padded to a multiple */
+	/* of the algorithms block size */
+	plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8);
+
+	ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool,
+			plaintext_pad_len, 10);
+
+	pktmbuf_write(ut_params->ibuf, 0, plaintext_len,
+			tdata->plaintext.data);
+
+	/* Create ZUC session */
+	retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0],
+			RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+			RTE_CRYPTO_CIPHER_ZUC_EEA3,
+			tdata->key.data, tdata->key.len);
+	if (retval < 0)
+		return retval;
+
+	/* Clear mbuf payload */
+
+	pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data);
+
+	/* Create ZUC operation */
+	retval = create_wireless_algo_cipher_operation(tdata->iv.data,
+			tdata->iv.len, tdata->plaintext.len,
+			tdata->validCipherOffsetLenInBits.len,
+			RTE_CRYPTO_CIPHER_ZUC_EEA3);
+	if (retval < 0)
+		return retval;
+
+	ut_params->op = process_crypto_request(ts_params->valid_devs[0],
+						ut_params->op);
+	TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf");
+
+	ut_params->obuf = ut_params->op->sym->m_dst;
+	if (ut_params->obuf)
+		ciphertext = rte_pktmbuf_read(ut_params->obuf,
+			tdata->iv.len, plaintext_len, ciphertext_buffer);
+	else
+		ciphertext = rte_pktmbuf_read(ut_params->ibuf,
+			tdata->iv.len, plaintext_len, ciphertext_buffer);
+
+	/* Validate obuf */
+	TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len);
+
+	/* Validate obuf */
+	TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(
+		ciphertext,
+		tdata->ciphertext.data,
+		tdata->validCipherLenInBits.len,
+		"ZUC Ciphertext data not as expected");
+
+	return 0;
+}
+
+static int
 test_zuc_authentication(const struct zuc_hash_test_data *tdata)
 {
 	struct crypto_testsuite_params *ts_params = &testsuite_params;
@@ -3619,12 +3932,24 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
 }
 
 static int
+test_kasumi_encryption_test_case_1_sgl(void)
+{
+	return test_kasumi_encryption_sgl(&kasumi_test_case_1);
+}
+
+static int
 test_kasumi_encryption_test_case_1_oop(void)
 {
 	return test_kasumi_encryption_oop(&kasumi_test_case_1);
 }
 
 static int
+test_kasumi_encryption_test_case_1_oop_sgl(void)
+{
+	return test_kasumi_encryption_oop_sgl(&kasumi_test_case_1);
+}
+
+static int
 test_kasumi_encryption_test_case_2(void)
 {
 	return test_kasumi_encryption(&kasumi_test_case_2);
@@ -3696,6 +4021,13 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
 }
 
 static int
+test_snow3g_encryption_test_case_1_oop_sgl(void)
+{
+	return test_snow3g_encryption_oop_sgl(&snow3g_test_case_1);
+}
+
+
+static int
 test_snow3g_encryption_test_case_1_offset_oop(void)
 {
 	return test_snow3g_encryption_offset_oop(&snow3g_test_case_1);
@@ -3815,6 +4147,12 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
 }
 
 static int
+test_zuc_encryption_test_case_6_sgl(void)
+{
+	return test_zuc_encryption_sgl(&zuc_test_case_1);
+}
+
+static int
 test_zuc_hash_generate_test_case_1(void)
 {
 	return test_zuc_authentication(&zuc_hash_test_case_1);
@@ -3998,12 +4336,21 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
 
 	struct rte_crypto_sym_op *sym_op = ut_params->op->sym;
 
-	sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append(
-			ut_params->ibuf, auth_tag_len);
-	TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data,
-			"no room to append digest");
-	sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(
-			ut_params->ibuf, data_pad_len);
+	if (ut_params->obuf) {
+		sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append(
+				ut_params->obuf, auth_tag_len);
+		TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data,
+				"no room to append digest");
+		sym_op->auth.digest.phys_addr = sgl_pktmbuf_mtophys_offset(
+				ut_params->obuf, data_pad_len);
+	} else {
+		sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append(
+				ut_params->ibuf, auth_tag_len);
+		TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data,
+				"no room to append digest");
+		sym_op->auth.digest.phys_addr = sgl_pktmbuf_mtophys_offset(
+				ut_params->ibuf, data_pad_len);
+	}
 	sym_op->auth.digest.length = auth_tag_len;
 
 	if (op == RTE_CRYPTO_CIPHER_OP_DECRYPT) {
@@ -4050,6 +4397,11 @@ static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata)
 	TEST_HEXDUMP(stdout, "aad:",
 			sym_op->auth.aad.data, aad_len);
 
+	if (ut_params->obuf) {
+		rte_pktmbuf_prepend(ut_params->obuf, iv_pad_len);
+		rte_pktmbuf_prepend(ut_params->obuf, aad_buffer_len);
+	}
+
 	sym_op->cipher.data.length = data_len;
 	sym_op->cipher.data.offset = aad_buffer_len + iv_pad_len;
 
@@ -6312,6 +6664,14 @@ struct test_crypto_vector {
 }
 
 static int
+test_AES_GCM_auth_encrypt_SGL_out_of_place_400B_1seg(void)
+{
+	return test_AES_GCM_authenticated_encryption_SGL(
+			&gcm_test_case_8, OUT_OF_PLACE, 400,
+			gcm_test_case_8.plaintext.len);
+}
+
+static int
 test_AES_GCM_auth_encrypt_SGL_in_place_1500B(void)
 {
 
@@ -6683,6 +7043,10 @@ struct test_crypto_vector {
 		TEST_CASE_ST(ut_setup, ut_teardown,
 			test_AES_GMAC_authentication_verify_test_case_4),
 
+		/** Scatter-Gather */
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_AES_GCM_auth_encrypt_SGL_out_of_place_400B_1seg),
+
 		/** Negative tests */
 		TEST_CASE_ST(ut_setup, ut_teardown,
 			authentication_verify_HMAC_SHA1_fail_data_corrupt),
@@ -6751,6 +7115,8 @@ struct test_crypto_vector {
 		TEST_CASE_ST(ut_setup, ut_teardown,
 			test_kasumi_encryption_test_case_1),
 		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_kasumi_encryption_test_case_1_sgl),
+		TEST_CASE_ST(ut_setup, ut_teardown,
 			test_kasumi_encryption_test_case_2),
 		TEST_CASE_ST(ut_setup, ut_teardown,
 			test_kasumi_encryption_test_case_3),
@@ -6773,6 +7139,10 @@ struct test_crypto_vector {
 		TEST_CASE_ST(ut_setup, ut_teardown,
 			test_kasumi_encryption_test_case_1_oop),
 		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_kasumi_encryption_test_case_1_oop_sgl),
+
+
+		TEST_CASE_ST(ut_setup, ut_teardown,
 			test_kasumi_decryption_test_case_1_oop),
 
 		/** KASUMI hash only (UIA1) */
@@ -6825,6 +7195,8 @@ struct test_crypto_vector {
 		TEST_CASE_ST(ut_setup, ut_teardown,
 			test_snow3g_encryption_test_case_1_oop),
 		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_snow3g_encryption_test_case_1_oop_sgl),
+		TEST_CASE_ST(ut_setup, ut_teardown,
 			test_snow3g_decryption_test_case_1_oop),
 
 		TEST_CASE_ST(ut_setup, ut_teardown,
@@ -6902,6 +7274,8 @@ struct test_crypto_vector {
 			test_zuc_hash_generate_test_case_4),
 		TEST_CASE_ST(ut_setup, ut_teardown,
 			test_zuc_hash_generate_test_case_5),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_zuc_encryption_test_case_6_sgl),
 		TEST_CASES_END() /**< NULL terminate unit test array */
 	}
 };
diff --git a/app/test/test_cryptodev.h b/app/test/test_cryptodev.h
index a9089aa..77cd826 100644
--- a/app/test/test_cryptodev.h
+++ b/app/test/test_cryptodev.h
@@ -71,4 +71,143 @@
 #define TRUNCATED_DIGEST_BYTE_LENGTH_SHA384		(24)
 #define TRUNCATED_DIGEST_BYTE_LENGTH_SHA512		(32)
 
+/**
+ * Write (spread) data from buffer to mbuf data
+ *
+ * @param mbuf
+ *   Destination mbuf
+ * @param offset
+ *   Start offset in mbuf
+ * @param len
+ *   Number of bytes to copy
+ * @param buffer
+ *   Continuous source buffer
+ */
+static inline void
+pktmbuf_write(struct rte_mbuf *mbuf, int offset, int len, const uint8_t *buffer)
+{
+	int n = len;
+	int l;
+	struct rte_mbuf *m;
+	char *dst;
+
+	for (m = mbuf; (m != NULL) && (offset > m->data_len); m = m->next)
+		offset -= m->data_len;
+
+	l = m->data_len - offset;
+
+	/* copy data from first segment */
+	dst = rte_pktmbuf_mtod_offset(m, char *, offset);
+	if (len <= l) {
+		rte_memcpy(dst, buffer, len);
+		return;
+	}
+
+	rte_memcpy(dst, buffer, l);
+	buffer += l;
+	n -= l;
+
+	for (m = m->next; (m != NULL) && (n > 0); m = m->next) {
+		dst = rte_pktmbuf_mtod(m, char *);
+		l = m->data_len;
+		if (n < l) {
+			rte_memcpy(dst, buffer, n);
+			return;
+		}
+		rte_memcpy(dst, buffer, l);
+		buffer += l;
+		n -= l;
+	}
+}
+
+static inline uint8_t *
+sgl_pktmbuf_mtod_offset(struct rte_mbuf *mbuf, int offset) {
+	struct rte_mbuf *m;
+
+	for (m = mbuf; (m != NULL) && (offset > m->data_len); m = m->next)
+		offset -= m->data_len;
+
+	if (!m) {
+		printf("sgl_pktmbuf_mtod_offset: offset out of buffer\n");
+		return NULL;
+	}
+	return rte_pktmbuf_mtod_offset(m, uint8_t *, offset);
+}
+
+static inline phys_addr_t
+sgl_pktmbuf_mtophys_offset(struct rte_mbuf *mbuf, int offset) {
+	struct rte_mbuf *m;
+
+	for (m = mbuf; (m != NULL) && (offset > m->data_len); m = m->next)
+		offset -= m->data_len;
+
+	if (!m) {
+		printf("sgl_pktmbuf_mtophys_offset: offset out of buffer\n");
+		return 0;
+	}
+	return rte_pktmbuf_mtophys_offset(m, offset);
+}
+
+static inline struct rte_mbuf *
+create_segmented_mbuf(struct rte_mempool *mbuf_pool, int pkt_len,
+		int nb_segs) {
+
+	struct rte_mbuf *m = NULL, *mbuf = NULL;
+	uint8_t *dst;
+	int data_len = 0;
+	int i, size;
+	int t_len;
+
+	if (pkt_len < 1) {
+		printf("Packet size must be 1 or more (is %d)\n", pkt_len);
+		return NULL;
+	}
+
+	if (nb_segs < 1) {
+		printf("Number of segments must be 1 or more (is %d)\n",
+				nb_segs);
+		return NULL;
+	}
+
+	t_len = pkt_len >= nb_segs ? pkt_len / nb_segs : 1;
+	size = pkt_len;
+
+	/* Create chained mbuf_src and fill it generated data */
+	for (i = 0; size > 0; i++) {
+
+		m = rte_pktmbuf_alloc(mbuf_pool);
+		if (i == 0)
+			mbuf = m;
+
+		if (!m) {
+			printf("Cannot create segment for source mbuf");
+			goto fail;
+		}
+
+		/* Make sure if tailroom is zeroed */
+		memset(rte_pktmbuf_mtod(m, uint8_t *), 0,
+				rte_pktmbuf_tailroom(m));
+
+		data_len = size > t_len ? t_len : size;
+		dst = (uint8_t *)rte_pktmbuf_append(m, data_len);
+		if (!dst) {
+			printf("Cannot append %d bytes to the mbuf\n",
+					data_len);
+			goto fail;
+		}
+
+		if (mbuf != m)
+			rte_pktmbuf_chain(mbuf, m);
+
+		size -= data_len;
+
+	}
+	return mbuf;
+
+fail:
+	if (mbuf)
+		rte_pktmbuf_free(mbuf);
+	return NULL;
+}
+
 #endif /* TEST_CRYPTODEV_H_ */
diff --git a/app/test/test_cryptodev_aes_test_vectors.h b/app/test/test_cryptodev_aes_test_vectors.h
index 898aae1..e566548 100644
--- a/app/test/test_cryptodev_aes_test_vectors.h
+++ b/app/test/test_cryptodev_aes_test_vectors.h
@@ -858,6 +858,16 @@
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT
 	},
 	{
+		.test_descr = "AES-192-CTR XCBC Decryption Digest Verify "
+				"Scatter Gather",
+		.test_data = &aes_test_data_2,
+		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
+		.feature_mask = BLOCKCIPHER_TEST_FEATURE_SG |
+			BLOCKCIPHER_TEST_FEATURE_OOP,
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB |
+			BLOCKCIPHER_TEST_TARGET_PMD_QAT
+	},
+	{
 		.test_descr = "AES-256-CTR HMAC-SHA1 Encryption Digest",
 		.test_data = &aes_test_data_3,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
@@ -883,6 +893,18 @@
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT
 	},
 	{
+		.test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest "
+				"Scatter Gather",
+		.test_data = &aes_test_data_4,
+		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
+		.feature_mask = BLOCKCIPHER_TEST_FEATURE_SG |
+			BLOCKCIPHER_TEST_FEATURE_OOP,
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB |
+			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_QAT
+
+	},
+	{
 		.test_descr = "AES-128-CBC HMAC-SHA1 Decryption Digest "
 			"Verify",
 		.test_data = &aes_test_data_4,
@@ -926,6 +948,17 @@
 			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
 	},
 	{
+		.test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest "
+				"Scatter Gather Sessionless",
+		.test_data = &aes_test_data_6,
+		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
+		.feature_mask = BLOCKCIPHER_TEST_FEATURE_SESSIONLESS |
+			BLOCKCIPHER_TEST_FEATURE_SG |
+			BLOCKCIPHER_TEST_FEATURE_OOP,
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB |
+			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+	},
+	{
 		.test_descr = "AES-128-CBC HMAC-SHA512 Decryption Digest "
 			"Verify",
 		.test_data = &aes_test_data_6,
@@ -935,6 +968,17 @@
 			BLOCKCIPHER_TEST_TARGET_PMD_QAT
 	},
 	{
+		.test_descr = "AES-128-CBC HMAC-SHA512 Decryption Digest "
+			"Verify Scatter Gather",
+		.test_data = &aes_test_data_6,
+		.op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC,
+		.feature_mask = BLOCKCIPHER_TEST_FEATURE_SG |
+			BLOCKCIPHER_TEST_FEATURE_OOP,
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB |
+			BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL |
+			BLOCKCIPHER_TEST_TARGET_PMD_QAT
+	},
+	{
 		.test_descr = "AES-128-CBC XCBC Encryption Digest",
 		.test_data = &aes_test_data_7,
 		.op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN,
@@ -1045,6 +1089,14 @@
 			BLOCKCIPHER_TEST_TARGET_PMD_MB
 	},
 	{
+		.test_descr = "AES-192-CBC Encryption Scater gather",
+		.test_data = &aes_test_data_10,
+		.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
+		.feature_mask = BLOCKCIPHER_TEST_FEATURE_SG |
+			BLOCKCIPHER_TEST_FEATURE_OOP,
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+	},
+	{
 		.test_descr = "AES-192-CBC Decryption",
 		.test_data = &aes_test_data_10,
 		.op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
diff --git a/app/test/test_cryptodev_blockcipher.c b/app/test/test_cryptodev_blockcipher.c
index 03dd073..2290c66 100644
--- a/app/test/test_cryptodev_blockcipher.c
+++ b/app/test/test_cryptodev_blockcipher.c
@@ -41,6 +41,7 @@
 #include <rte_cryptodev_pmd.h>
 
 #include "test.h"
+#include "test_cryptodev.h"
 #include "test_cryptodev_blockcipher.h"
 #include "test_cryptodev_aes_test_vectors.h"
 #include "test_cryptodev_des_test_vectors.h"
@@ -63,6 +64,7 @@
 	struct rte_crypto_sym_op *sym_op = NULL;
 	struct rte_crypto_op *op = NULL;
 	struct rte_cryptodev_sym_session *sess = NULL;
+	struct rte_cryptodev_info dev_info;
 
 	int status = TEST_SUCCESS;
 	const struct blockcipher_test_data *tdata = t->test_data;
@@ -72,6 +74,19 @@
 	uint32_t digest_len = 0;
 	char *buf_p = NULL;
 
+	int nb_segs = 3;
+	int nb_segs_oop = 1;
+
+	if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SG) {
+		rte_cryptodev_info_get(dev_id, &dev_info);
+		if (!(dev_info.feature_flags &
+				RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) {
+			printf("Device doesn't support scatter-gather. "
+					"Test Skipped.\n");
+			return 0;
+		}
+	}
+
 	if (tdata->cipher_key.len)
 		memcpy(cipher_key, tdata->cipher_key.data,
 			tdata->cipher_key.len);
@@ -96,72 +111,112 @@
 	}
 
 	/* preparing data */
-	ibuf = rte_pktmbuf_alloc(mbuf_pool);
-	if (!ibuf) {
-		snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
-			"line %u FAILED: %s",
-			__LINE__, "Allocation of rte_mbuf failed");
-		status = TEST_FAILED;
-		goto error_exit;
-	}
 
 	if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER)
 		buf_len += tdata->iv.len;
 	if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH)
 		buf_len += digest_len;
 
-	buf_p = rte_pktmbuf_append(ibuf, buf_len);
-	if (!buf_p) {
-		snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
-			"line %u FAILED: %s",
-			__LINE__, "No room to append mbuf");
-		status = TEST_FAILED;
-		goto error_exit;
-	}
+	if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SG) {
 
-	if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) {
-		rte_memcpy(buf_p, tdata->iv.data, tdata->iv.len);
-		buf_p += tdata->iv.len;
-	}
+		if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) {
+			ibuf = create_segmented_mbuf(mbuf_pool,
+					tdata->plaintext.len, nb_segs);
+			pktmbuf_write(ibuf, 0, tdata->plaintext.len,
+					tdata->plaintext.data);
+		} else {
+			ibuf = create_segmented_mbuf(mbuf_pool,
+					tdata->ciphertext.len, nb_segs);
+			pktmbuf_write(ibuf, 0, tdata->ciphertext.len,
+					tdata->ciphertext.data);
+		}
 
-	/* only encryption requires plaintext.data input,
-	 * decryption/(digest gen)/(digest verify) use ciphertext.data
-	 * to be computed
-	 */
-	if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) {
-		rte_memcpy(buf_p, tdata->plaintext.data,
-			tdata->plaintext.len);
-		buf_p += tdata->plaintext.len;
-	} else {
-		rte_memcpy(buf_p, tdata->ciphertext.data,
-			tdata->ciphertext.len);
-		buf_p += tdata->ciphertext.len;
-	}
+		if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) {
+			rte_memcpy(rte_pktmbuf_prepend(ibuf, tdata->iv.len),
+					tdata->iv.data, tdata->iv.len);
+		}
 
-	if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY)
-		rte_memcpy(buf_p, tdata->digest.data, digest_len);
-	else
-		memset(buf_p, 0, digest_len);
+		buf_p = rte_pktmbuf_append(ibuf, digest_len);
+		if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY)
+			rte_memcpy(buf_p, tdata->digest.data, digest_len);
+		else
+			memset(buf_p, 0, digest_len);
 
-	if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) {
-		obuf = rte_pktmbuf_alloc(mbuf_pool);
-		if (!obuf) {
-			snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u "
-				"FAILED: %s", __LINE__,
-				"Allocation of rte_mbuf failed");
+	} else {
+		ibuf = rte_pktmbuf_alloc(mbuf_pool);
+		if (!ibuf) {
+			snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
+					"line %u FAILED: %s",
+					__LINE__,
+					"Allocation of rte_mbuf failed");
 			status = TEST_FAILED;
 			goto error_exit;
 		}
 
-		buf_p = rte_pktmbuf_append(obuf, buf_len);
+		buf_p = rte_pktmbuf_append(ibuf, buf_len);
 		if (!buf_p) {
-			snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u "
-				"FAILED: %s", __LINE__,
-				"No room to append mbuf");
+			snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
+					"line %u FAILED: %s",
+					__LINE__, "No room to append mbuf");
 			status = TEST_FAILED;
 			goto error_exit;
 		}
-		memset(buf_p, 0, buf_len);
+
+		if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) {
+			rte_memcpy(buf_p, tdata->iv.data, tdata->iv.len);
+			buf_p += tdata->iv.len;
+		}
+
+		/* only encryption requires plaintext.data input,
+		 * decryption/(digest gen)/(digest verify) use ciphertext.data
+		 * to be computed
+		 */
+		if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) {
+			rte_memcpy(buf_p, tdata->plaintext.data,
+					tdata->plaintext.len);
+			buf_p += tdata->plaintext.len;
+		} else {
+			rte_memcpy(buf_p, tdata->ciphertext.data,
+					tdata->ciphertext.len);
+			buf_p += tdata->ciphertext.len;
+		}
+
+		if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY)
+			rte_memcpy(buf_p, tdata->digest.data, digest_len);
+		else
+			memset(buf_p, 0, digest_len);
+	}
+
+	if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) {
+		if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SG) {
+			obuf = create_segmented_mbuf(mbuf_pool, buf_len,
+					nb_segs_oop);
+			if (!obuf) {
+				snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
+						"line %u FAILED: %s", __LINE__,
+						"Allocation of rte_mbuf failed");
+				status = TEST_FAILED;
+				goto error_exit;
+			}
+		} else {
+			obuf = rte_pktmbuf_alloc(mbuf_pool);
+			if (!obuf) {
+				snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
+						"line %u FAILED: %s", __LINE__,
+						"Allocation of rte_mbuf failed");
+				status = TEST_FAILED;
+				goto error_exit;
+			}
+			buf_p = rte_pktmbuf_append(obuf, buf_len);
+			if (!buf_p) {
+				snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN,
+						"line %u FAILED: %s", __LINE__,
+						"No room to append mbuf");
+				status = TEST_FAILED;
+				goto error_exit;
+			}
+			memset(buf_p, 0, buf_len);
+		}
 	}
 
 	/* Generate Crypto op data structure */
@@ -307,17 +362,17 @@
 
 		if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_GEN) {
 			auth_xform->auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
-			sym_op->auth.digest.data = rte_pktmbuf_mtod_offset
-				(iobuf, uint8_t *, digest_offset);
+			sym_op->auth.digest.data = sgl_pktmbuf_mtod_offset
+				(iobuf, digest_offset);
 			sym_op->auth.digest.phys_addr =
-				rte_pktmbuf_mtophys_offset(iobuf,
+				sgl_pktmbuf_mtophys_offset(iobuf,
 					digest_offset);
 		} else {
 			auth_xform->auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
-			sym_op->auth.digest.data = rte_pktmbuf_mtod_offset
-				(sym_op->m_src, uint8_t *, digest_offset);
+			sym_op->auth.digest.data = sgl_pktmbuf_mtod_offset
+				(sym_op->m_src, digest_offset);
 			sym_op->auth.digest.phys_addr =
-				rte_pktmbuf_mtophys_offset(sym_op->m_src,
+				sgl_pktmbuf_mtophys_offset(sym_op->m_src,
 					digest_offset);
 		}
 
@@ -386,13 +441,10 @@
 	}
 
 	if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) {
-		uint8_t *crypto_res;
+		uint8_t buffer[2048];
 		const uint8_t *compare_ref;
 		uint32_t compare_len;
 
-		crypto_res = rte_pktmbuf_mtod_offset(iobuf, uint8_t *,
-			tdata->iv.len);
-
 		if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) {
 			compare_ref = tdata->ciphertext.data;
 			compare_len = tdata->ciphertext.len;
@@ -401,7 +453,8 @@
 			compare_len = tdata->plaintext.len;
 		}
 
-		if (memcmp(crypto_res, compare_ref, compare_len)) {
+		if (memcmp(rte_pktmbuf_read(iobuf, tdata->iv.len, compare_len,
+				buffer), compare_ref, compare_len)) {
 			snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u "
 				"FAILED: %s", __LINE__,
 				"Crypto data not as expected");
@@ -414,12 +467,11 @@
 		uint8_t *auth_res;
 
 		if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER)
-			auth_res = rte_pktmbuf_mtod_offset(iobuf,
-				uint8_t *,
-				tdata->iv.len + tdata->ciphertext.len);
+			auth_res = sgl_pktmbuf_mtod_offset(iobuf,
+					tdata->iv.len + tdata->ciphertext.len);
 		else
-			auth_res = rte_pktmbuf_mtod_offset(iobuf,
-				uint8_t *, tdata->ciphertext.len);
+			auth_res = sgl_pktmbuf_mtod_offset(iobuf,
+					tdata->ciphertext.len);
 
 		if (memcmp(auth_res, tdata->digest.data, digest_len)) {
 			snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u "
diff --git a/app/test/test_cryptodev_blockcipher.h b/app/test/test_cryptodev_blockcipher.h
index fe97e4c..7256f6b 100644
--- a/app/test/test_cryptodev_blockcipher.h
+++ b/app/test/test_cryptodev_blockcipher.h
@@ -45,6 +45,7 @@
 #define BLOCKCIPHER_TEST_FEATURE_OOP			0x01
 #define BLOCKCIPHER_TEST_FEATURE_SESSIONLESS	0x02
 #define BLOCKCIPHER_TEST_FEATURE_STOPPER	0x04 /* stop upon failing */
+#define BLOCKCIPHER_TEST_FEATURE_SG		0x08 /* Scatter Gather */
 
 #define BLOCKCIPHER_TEST_TARGET_PMD_MB		0x0001 /* Multi-buffer flag */
 #define BLOCKCIPHER_TEST_TARGET_PMD_QAT			0x0002 /* QAT flag */
diff --git a/app/test/test_cryptodev_gcm_test_vectors.h b/app/test/test_cryptodev_gcm_test_vectors.h
index df984fc..45ea3d4 100644
--- a/app/test/test_cryptodev_gcm_test_vectors.h
+++ b/app/test/test_cryptodev_gcm_test_vectors.h
@@ -450,6 +450,559 @@ struct gmac_test_data {
 	}
 };
 
+static const struct gcm_test_data gcm_test_case_8 = {
+	.key = {
+		.data = {
+			0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+			0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08
+		},
+		.len = 16
+	},
+	.iv = {
+		.data = {
+			0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+			0xde, 0xca, 0xf8, 0x88
+		},
+		.len = 12
+	},
+	.aad = {
+		.data = {
+			0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+			0xfe, 0xed, 0xfa, 0xce
+		},
+		.len = 12
+	},
+	.plaintext = {
+		.data = {
+			0xC5, 0x34, 0x2E, 0x83, 0xEB, 0x4C, 0x02, 0x03,
+			0xF7, 0xB2, 0x57, 0x35, 0x26, 0x81, 0x63, 0xAE,
+			0x1F, 0xCD, 0x2D, 0x02, 0x91, 0x5A, 0xDB, 0x3A,
+			0xF1, 0x38, 0xD8, 0x75, 0x86, 0x20, 0xCC, 0x1E,
+			0xE6, 0xDC, 0xFF, 0xB5, 0xEA, 0x0E, 0x18, 0x7A,
+			0x86, 0x6C, 0xAB, 0x39, 0x2D, 0x90, 0xAC, 0x77,
+			0x5D, 0xED, 0x65, 0xB3, 0x05, 0x29, 0xBB, 0x09,
+			0xD0, 0x21, 0x74, 0x6A, 0x67, 0x1C, 0x95, 0x42,
+			0x55, 0xAD, 0xC8, 0x91, 0x28, 0xFE, 0x16, 0x9A,
+			0xE1, 0xCB, 0xCD, 0x68, 0x3B, 0xDF, 0x3E, 0x3A,
+			0x34, 0xFE, 0x9B, 0xFB, 0xF5, 0x15, 0x2A, 0x29,
+			0x18, 0x99, 0x24, 0xBF, 0xB6, 0x43, 0xDB, 0xD1,
+			0x69, 0x26, 0x1E, 0x31, 0x2C, 0x8C, 0x3C, 0x6B,
+			0x7F, 0x06, 0xA6, 0x03, 0xE2, 0x1A, 0x50, 0xFE,
+			0x7C, 0x69, 0xE5, 0x5F, 0x35, 0x93, 0xE9, 0x20,
+			0x14, 0xB1, 0xCA, 0x61, 0xE7, 0x9C, 0x89, 0x08,
+			0xD6, 0xB1, 0xC2, 0x63, 0x1B, 0x86, 0x5E, 0xF1,
+			0xF5, 0x23, 0x0E, 0x9B, 0xE5, 0xBD, 0x5D, 0x04,
+			0xF7, 0xEF, 0x8E, 0x46, 0xB0, 0x11, 0x4F, 0x69,
+			0x62, 0x35, 0x51, 0xB7, 0x24, 0xA2, 0x31, 0xD0,
+			0x32, 0x4E, 0xB8, 0x44, 0xC7, 0x59, 0xDE, 0x25,
+			0xEA, 0x2D, 0x00, 0x0E, 0xF1, 0x07, 0xBA, 0xBB,
+			0x9A, 0xBC, 0x4F, 0x57, 0xB7, 0x13, 0x57, 0xEF,
+			0xD9, 0xF6, 0x80, 0x69, 0xEA, 0xE8, 0x47, 0x9C,
+			0x51, 0x71, 0xE6, 0x8F, 0x69, 0x29, 0xB4, 0x60,
+			0xE8, 0x50, 0xE5, 0xD0, 0x9B, 0xD2, 0x62, 0x6F,
+			0x09, 0x5C, 0xD1, 0x4B, 0x85, 0xE2, 0xFD, 0xD3,
+			0xEB, 0x28, 0x55, 0x77, 0x97, 0xCA, 0xD6, 0xA8,
+			0xDC, 0x35, 0x68, 0xF7, 0x6A, 0xCF, 0x48, 0x3F,
+			0x49, 0x31, 0x00, 0x65, 0xB7, 0x31, 0x1A, 0x49,
+			0x75, 0xDE, 0xCE, 0x7F, 0x18, 0xB5, 0x31, 0x9A,
+			0x64, 0x6D, 0xE5, 0x49, 0x1D, 0x6D, 0xF2, 0x21,
+			0x9F, 0xF5, 0xFF, 0x7C, 0x41, 0x30, 0x33, 0x06,
+			0x7B, 0xA4, 0xD8, 0x99, 0xF6, 0xCC, 0xDF, 0xC4,
+			0x3F, 0xF3, 0xCD, 0xE7, 0x74, 0xC4, 0x4A, 0x19,
+			0x5C, 0xCA, 0x42, 0x31, 0xF1, 0x3B, 0x65, 0x1C,
+			0x3D, 0x56, 0x08, 0xBE, 0x15, 0x37, 0x23, 0x50,
+			0xD6, 0xA3, 0x57, 0x64, 0x25, 0xBE, 0xDA, 0xC2,
+			0x4E, 0xF5, 0x1A, 0xAD, 0x6F, 0x43, 0x78, 0x21,
+			0xF9, 0x36, 0x39, 0x1F, 0x5F, 0xF7, 0x1B, 0xA0,
+			0xEE, 0x8B, 0x4F, 0x8A, 0x9D, 0xD8, 0xED, 0x37,
+			0xCE, 0x0D, 0x70, 0xE0, 0x3F, 0xE7, 0x11, 0x30,
+			0x17, 0x1D, 0x03, 0x5E, 0xA0, 0x3D, 0x3F, 0x9E,
+			0xF5, 0xD3, 0x74, 0x2E, 0xC1, 0xD6, 0xFF, 0xF7,
+			0x2E, 0xE7, 0x80, 0x88, 0xCF, 0x0E, 0x7F, 0x12,
+			0x71, 0x62, 0xC7, 0xF1, 0xC4, 0x2B, 0x64, 0x5D,
+			0x1C, 0x9A, 0xB4, 0xCB, 0xB8, 0x24, 0xB3, 0x0B,
+			0x33, 0xF2, 0x8A, 0x8F, 0x76, 0xC8, 0x81, 0xDA,
+			0x1A, 0x10, 0xB5, 0xA9, 0xCD, 0xDC, 0x1A, 0x02,
+			0xC1, 0xAE, 0x4F, 0x02, 0x1B, 0x13, 0x96, 0x5A,
+			0x2E, 0x03, 0xA2, 0x68, 0xB2, 0x29, 0xAC, 0x28,
+			0xB8, 0xDC, 0xD5, 0x27, 0x55, 0xEC, 0x43, 0xDC,
+			0xB7, 0x49, 0x1D, 0xE1, 0x30, 0x25, 0x81, 0xA6,
+			0x90, 0x1F, 0x75, 0xBA, 0x19, 0x1E, 0xF7, 0xC5,
+			0x77, 0x35, 0xEE, 0x68, 0x71, 0x22, 0xA0, 0xB4,
+			0xCC, 0x99, 0x86, 0x1B, 0x1B, 0xC8, 0x27, 0xFC,
+			0x6D, 0x8D, 0xE7, 0x8B, 0xC3, 0x40, 0x3D, 0xA8,
+			0xCB, 0x9B, 0xC4, 0x12, 0x07, 0xDD, 0xA1, 0x92,
+			0xE5, 0x80, 0x7A, 0xF4, 0xDB, 0x4C, 0xE6, 0xEE,
+			0xF9, 0xD5, 0x1C, 0x20, 0x18, 0xD3, 0x8F, 0xDF,
+			0x1C, 0xD3, 0x51, 0x4E, 0x0E, 0xED, 0x06, 0x61,
+			0xF7, 0xBA, 0x81, 0x3A, 0x2F, 0xEA, 0xED, 0x70,
+			0xA9, 0xD9, 0x54, 0x4D, 0xFC, 0x1D, 0x19, 0xEA,
+			0xA6, 0x39, 0x8C, 0x6C, 0x78, 0xA8, 0x05, 0xEB,
+			0xF2, 0xB5, 0xDE, 0x06, 0x9D, 0x8A, 0x78, 0x2A,
+			0xF5, 0x50, 0xA4, 0xBD, 0x9B, 0xDA, 0xCA, 0x66,
+			0xC0, 0x23, 0xAB, 0xE8, 0x95, 0x7E, 0xC9, 0xD2,
+			0x6F, 0x09, 0xF2, 0x9A, 0x17, 0x89, 0xDA, 0x47,
+			0x65, 0x8C, 0x20, 0xFA, 0x4E, 0x86, 0x18, 0xEB,
+			0x7C, 0x08, 0xEC, 0x8A, 0x05, 0x54, 0x96, 0xD2,
+			0x7A, 0x8A, 0x81, 0x58, 0x75, 0x8C, 0x7B, 0x02,
+			0xEE, 0x1F, 0x51, 0x88, 0xD0, 0xD1, 0x90, 0x99,
+			0x0C, 0xAE, 0x51, 0x2E, 0x54, 0x3E, 0xB1, 0x7D,
+			0xBC, 0xE8, 0x54, 0x93, 0x6D, 0x10, 0x3C, 0xC6,
+			0x71, 0xF6, 0xF5, 0x0B, 0x07, 0x0A, 0x6E, 0x59,
+			0x20, 0x45, 0x21, 0x7D, 0x37, 0x64, 0x92, 0x09,
+			0xA7, 0xE2, 0x34, 0x6F, 0xFC, 0xCC, 0x66, 0x0E,
+			0x88, 0x1B, 0x19, 0x86, 0x11, 0xD7, 0x81, 0x25,
+			0xF1, 0x8A, 0x03, 0xB7, 0x7A, 0xF0, 0x98, 0x4A,
+			0x5C, 0xA1, 0x6D, 0x85, 0xA4, 0x8C, 0x4B, 0x65,
+			0x9F, 0x72, 0x64, 0x14, 0xBA, 0x74, 0xEE, 0xA3,
+			0x88, 0xFE, 0x1B, 0xCF, 0x11, 0x4F, 0xD1, 0xAC,
+			0xFA, 0x14, 0xC3, 0xA7, 0xDD, 0x06, 0x85, 0x4E,
+			0x64, 0x06, 0x92, 0x9C, 0xDF, 0x06, 0x09, 0xF1,
+			0x4D, 0xE8, 0xF8, 0x2F, 0x69, 0xB6, 0x8A, 0xAF,
+			0x25, 0x21, 0xB5, 0x48, 0x59, 0xF8, 0x9D, 0x60,
+			0xAE, 0x42, 0x11, 0x7A, 0x68, 0x4D, 0x7E, 0x76,
+			0xB0, 0xD2, 0xE3, 0xD9, 0x24, 0x16, 0x20, 0x0A,
+			0xEB, 0xE0, 0x68, 0xCB, 0xBC, 0xAB, 0x67, 0xE4,
+			0xF3, 0x25, 0x1F, 0xD3, 0x85, 0xA7, 0x1D, 0x7E,
+			0x3C, 0x63, 0xCB, 0xC2, 0x50, 0x90, 0x0F, 0x4B,
+			0x6E, 0x68, 0x06, 0x84, 0x65, 0xF7, 0xD0, 0xD4,
+			0x12, 0xED, 0xFA, 0xC9, 0x40, 0xE2, 0xC0, 0xC9,
+			0x46, 0x22, 0x47, 0x5E, 0x6D, 0xC1, 0x63, 0xDB,
+			0x51, 0x98, 0xDA, 0x1A, 0xC4, 0xB9, 0xED, 0xE9,
+			0x09, 0xB9, 0xCF, 0x91, 0x04, 0x1C, 0x63, 0xD8,
+			0xC5, 0xA5, 0xAE, 0x53, 0x7B, 0xA1, 0x29, 0x83,
+			0x37, 0xFB, 0xBF, 0x96, 0xBB, 0x24, 0x3D, 0x77,
+			0x8C, 0x0F, 0xB3, 0x4B, 0x66, 0x9C, 0x54, 0xBB,
+			0xF6, 0xDD, 0xD1, 0xB4, 0xD2, 0xF6, 0xAA, 0xED,
+			0x18, 0x56, 0x63, 0x3E, 0x0B, 0xCA, 0xAB, 0x70,
+			0xBB, 0x63, 0xEA, 0xB1, 0x00, 0x65, 0x90, 0x18,
+			0xB8, 0x63, 0xA2, 0xF2, 0xB6, 0x1E, 0x61, 0x7B,
+			0xD5, 0x01, 0xD9, 0x4D, 0xC9, 0x9D, 0x99, 0xC1,
+			0x57, 0x9D, 0x6F, 0xAE, 0x64, 0xE4, 0x0C, 0x7E,
+			0xFA, 0x15, 0x5E, 0xB6, 0x43, 0xB8, 0x8B, 0x89,
+			0x87, 0xCD, 0x4F, 0xAD, 0x30, 0x1E, 0xA5, 0x03,
+			0x7A, 0xC2, 0x10, 0x42, 0x14, 0x88, 0xD6, 0x7A,
+			0x6D, 0x56, 0x52, 0x2E, 0x8D, 0x1B, 0x5D, 0x36,
+			0x27, 0xA0, 0x21, 0x4B, 0x64, 0xF0, 0xC5, 0x41,
+			0xAD, 0x05, 0x4A, 0x24, 0xE4, 0x70, 0x88, 0x63,
+			0x12, 0xD0, 0xBC, 0x05, 0x38, 0xD9, 0x41, 0x68,
+			0x9F, 0x16, 0x9A, 0x54, 0x09, 0x21, 0x64, 0x36,
+			0x63, 0x97, 0x3A, 0xB5, 0xE0, 0x25, 0x43, 0x8A,
+			0x6A, 0x59, 0x97, 0xC1, 0x31, 0xA5, 0x66, 0xD2,
+			0xF0, 0x1C, 0xDF, 0x97, 0x51, 0xD0, 0x61, 0xBA,
+			0x55, 0x5F, 0xD7, 0x0D, 0xD4, 0x75, 0x8E, 0x79,
+			0x04, 0x75, 0x00, 0xB9, 0xC0, 0x7A, 0x66, 0x05,
+			0x9F, 0x2B, 0x44, 0x42, 0x75, 0x0F, 0xD5, 0x15,
+			0xD6, 0x16, 0x8F, 0x6C, 0x6E, 0xD4, 0x37, 0xCF,
+			0xB4, 0xDA, 0x93, 0x00, 0x11, 0xFB, 0xBE, 0xEE,
+			0x3B, 0x6D, 0x1D, 0xBA, 0x33, 0xD1, 0x52, 0x8B,
+			0x16, 0x39, 0x42, 0x27, 0xE6, 0x56, 0x4C, 0x41,
+			0x91, 0xB0, 0x98, 0xAE, 0x9B, 0x2D, 0x9B, 0x23,
+			0x80, 0x4C, 0xEA, 0x98, 0x57, 0x95, 0x28, 0x94,
+			0x43, 0xD3, 0x88, 0x12, 0xDF, 0x89, 0x5A, 0x7B,
+			0xC5, 0xCB, 0x36, 0x54, 0x65, 0x74, 0xB8, 0x4E,
+			0xE2, 0x4D, 0x01, 0xD5, 0x9C, 0x82, 0xB9, 0x1A,
+			0x09, 0xD2, 0xCE, 0x04, 0x36, 0xD8, 0x41, 0xAC,
+			0x4C, 0xAD, 0xC6, 0x52, 0x91, 0x1A, 0x06, 0x6D,
+			0xFC, 0xAB, 0x29, 0x93, 0x87, 0x88, 0xB9, 0x8C,
+			0xFA, 0x57, 0x2B, 0x05, 0x03, 0xD0, 0x18, 0xED,
+			0x7A, 0x7B, 0x81, 0x6A, 0x97, 0x65, 0x5B, 0x90,
+			0xDE, 0xA9, 0xFC, 0x8F, 0xFC, 0xBB, 0x98, 0xD8,
+			0xFA, 0x32, 0x3F, 0x3F, 0x7F, 0x74, 0x65, 0x38,
+			0xC4, 0x28, 0xEC, 0x27, 0x1F, 0x28, 0x01, 0xB1,
+			0xAF, 0x2B, 0x8A, 0x05, 0x38, 0x7B, 0x77, 0xC9,
+			0x61, 0x77, 0x34, 0x2C, 0x22, 0xE5, 0xEB, 0xDC,
+			0x9D, 0x18, 0x6E, 0x23, 0x25, 0x52, 0x69, 0xB7,
+			0x05, 0xDB, 0x66, 0x5D, 0xEA, 0x76, 0x83, 0x82,
+			0x97, 0x39, 0xAF, 0xC0, 0x50, 0x81, 0x18, 0x0D,
+			0x22, 0xFA, 0xB7, 0x44, 0x5C, 0x3F, 0x69, 0xF3,
+			0xAC, 0xC5, 0x63, 0x9F, 0xD8, 0x72, 0x7E, 0x9A,
+			0xC2, 0xEB, 0x79, 0xD0, 0x74, 0x65, 0xE8, 0xCA,
+			0xFD, 0xA8, 0x7D, 0x23, 0x07, 0x99, 0x3E, 0xAF,
+			0xDB, 0x67, 0x10, 0xC0, 0xE5, 0x61, 0x77, 0xC6,
+			0x8D, 0xC4, 0x0E, 0xAA, 0x55, 0xE3, 0xC0, 0xC7,
+			0xA5, 0x36, 0x28, 0x61, 0xDB, 0x16, 0x96, 0x5E,
+			0x01, 0x47, 0x82, 0xE3, 0xEB, 0x20, 0x3F, 0x10,
+			0xFA, 0x5A, 0xBC, 0xD3, 0xF9, 0xCE, 0x04, 0x87,
+			0x51, 0x07, 0xF9, 0xD0, 0xE7, 0x6D, 0xCB, 0xCC,
+			0xC4, 0x15, 0x00, 0xE2, 0xDC, 0x8E, 0x7B, 0x5C,
+			0x9A, 0xF2, 0x78, 0x70, 0x4D, 0xA1, 0xAA, 0xB5,
+			0x13, 0xCC, 0x71, 0x66, 0x5A, 0x79, 0x13, 0x3B,
+			0x12, 0xCD, 0x40, 0x30, 0x5A, 0x49, 0xD4, 0x20,
+			0xED, 0xCF, 0x4A, 0x75, 0xE6, 0xD5, 0xDD, 0x0F,
+			0xD4, 0xBE, 0x98, 0x9F, 0xD7, 0x1F, 0xC0, 0x02,
+			0x31, 0xFA, 0x67, 0x37, 0x25, 0x86, 0x56, 0x85,
+			0x2B, 0xA2, 0x57, 0xCD, 0x8E, 0x74, 0xE7, 0x69,
+			0xEE, 0x33, 0x5A, 0x3F, 0xCD, 0x1E, 0xE3, 0xB9,
+			0xAA, 0x52, 0xF5, 0x22, 0x4E, 0xE3, 0xFF, 0xC8,
+			0xE3, 0x13, 0xA3, 0x9A, 0x63, 0x23, 0xC3, 0xD7,
+			0xE5, 0x88, 0x3E, 0x0A, 0x4B, 0xA5, 0x01, 0xE6,
+			0x13, 0xCF, 0xED, 0xEE, 0x2A, 0x58, 0x09, 0x3F,
+			0x2F, 0x28, 0xE7, 0xC4, 0x6B, 0xEC, 0x49, 0x51,
+			0x79, 0x8F, 0xD5, 0x19, 0x5D, 0xA5, 0x10, 0xCE,
+			0x8E, 0xF6, 0x26, 0x78, 0x7A, 0xA8, 0x11, 0x52,
+			0x5F, 0x97, 0x14, 0xC9, 0x29, 0x87, 0xB8, 0xA0,
+			0x2D, 0xE6, 0xA7, 0x2A, 0xD4, 0xFF, 0xEB, 0xBA,
+			0xFD, 0x58, 0x39, 0x33, 0xB1, 0xCE, 0x0E, 0x78,
+			0x67, 0x1E, 0xA1, 0x92, 0x77, 0x63, 0xF8, 0xC0,
+			0x02, 0x49, 0x73, 0xC0, 0xA1, 0x26, 0x83, 0x04,
+			0x9A, 0x5D, 0x85, 0x68, 0x2A, 0x2F, 0xCB, 0x88,
+			0x8D, 0x14, 0xB1, 0x33, 0xFA, 0xFB, 0xE9, 0x05,
+			0xBE, 0x24, 0x1A, 0x6B, 0x29, 0x2B, 0x3F, 0x52,
+			0x8F, 0xFB, 0xE6, 0x02, 0x77, 0x50, 0x71, 0xDB,
+			0xE9, 0x92, 0x3F, 0xE1, 0x20, 0x62, 0x80, 0xAE,
+			0xA4, 0x98, 0xC6, 0xCD, 0xE0, 0xB1, 0xC3, 0x33,
+			0xB1, 0xC5, 0x91, 0x3C, 0x19, 0x34, 0xA8, 0xD9,
+			0xB3, 0x25, 0x69, 0xE3, 0x9C, 0x5F, 0x78, 0xD0,
+			0x83, 0x1F, 0xAB, 0x85, 0x13, 0x56, 0x69, 0xB5,
+			0x06, 0x47, 0x62, 0x37, 0x27, 0x15, 0x14, 0x05,
+			0x4A, 0xF4, 0x6A, 0x68, 0x2A, 0x6A, 0xC3, 0x5A,
+			0xDF, 0xB5, 0xAE, 0x2F, 0x8D, 0x8F, 0x21, 0xDB,
+			0x33, 0x00, 0x9B, 0xD4, 0xC4, 0x08, 0x3B, 0x81,
+			0x63, 0x4C, 0xB0, 0x39, 0x4C, 0x0A, 0xD5, 0x71,
+			0x3E, 0x5A, 0x50, 0x58, 0x9C, 0x07, 0x89, 0x79,
+			0x79, 0x2F, 0x0B, 0xD9, 0x50, 0xBC, 0xCF, 0x46,
+			0x7A, 0x68, 0x5C, 0xBF, 0x1E, 0x49, 0x77, 0x92,
+			0x85, 0x11, 0x39, 0xA6, 0x2F, 0xDA, 0x7B, 0xFA,
+			0x72, 0x87, 0x06, 0xCD, 0x84, 0x41, 0x20, 0x1B,
+			0x66, 0x3F, 0x42, 0x0C, 0x9E, 0x19, 0xD3, 0x18,
+			0x57, 0xA0, 0xEE, 0x16, 0x3A, 0xC7, 0xF9, 0xD3,
+			0x8B, 0xC9, 0x24, 0x70, 0x70, 0x51, 0x7C, 0x06,
+			0x68, 0xD3, 0x29, 0xC9, 0x85, 0x9A, 0x1C, 0xE6,
+			0x8C, 0x17, 0xF4, 0x88, 0xDF, 0xEA, 0xFF, 0x44,
+			0x8D, 0x54, 0xBE, 0x22, 0x07, 0xA5, 0x7C, 0x0C,
+			0xF4, 0x8D, 0xB1, 0x0C, 0x07, 0xED, 0xBD, 0x28,
+			0x19, 0xDA, 0x07, 0x71, 0xA8, 0xA1, 0xE0, 0xDD,
+			0xEE, 0x08, 0x18, 0xA5, 0xBD, 0xDD, 0x32, 0x0B,
+			0x70, 0x1C, 0xD9, 0xEE, 0x19, 0xC2, 0xAE, 0x5C,
+			0xE3, 0x02, 0x74, 0x70, 0x96, 0x61, 0xB1, 0x73,
+			0x3B, 0xD6, 0x74, 0xC0, 0x82, 0xA9, 0x1F, 0xE0,
+			0xF1, 0x22, 0x50, 0xF3, 0x9F, 0xE5, 0x13, 0x92,
+			0xFC, 0x0A, 0x1A, 0x3C, 0xB4, 0x46, 0xFB, 0x81,
+			0x00, 0x84, 0xA4, 0x5E, 0x6B, 0x8C, 0x25, 0x6E,
+			0xD7, 0xB7, 0x3B, 0x01, 0x65, 0xFB, 0x0B, 0x46,
+			0x67, 0x27, 0x2D, 0x51, 0xAD, 0xB5, 0xE0, 0x85,
+			0xC2, 0x95, 0xA3, 0xE3, 0x68, 0x4D, 0x9E, 0x8C,
+			0x11, 0x53, 0xF0, 0xB2, 0x85, 0xFA, 0x52, 0x4E,
+			0xEC, 0xF9, 0xB7, 0x3C, 0x89, 0x2C, 0x4D, 0x32,
+			0x9A, 0xCB, 0x17, 0xF3, 0x16, 0xBF, 0x44, 0x40,
+			0xE9, 0x5E, 0x51, 0x8C, 0x1E, 0x52, 0x0A, 0xC2,
+			0xCD, 0xA5, 0xAA, 0x03, 0x27, 0xB0, 0x8F, 0x64,
+			0xDB, 0xD7, 0x03, 0x01, 0x8A, 0x24, 0x28, 0x7E,
+			0x53, 0x6F, 0x24, 0xFD, 0xAA, 0xE3, 0x78, 0xB6,
+			0xA5, 0x5D, 0x5A, 0x67, 0x20, 0xE2, 0xBE, 0x3A,
+			0x2B, 0xE7, 0x86, 0x11, 0xDD, 0x96, 0xCB, 0x09,
+			0x65, 0xA0, 0x36, 0xF9, 0xB0, 0x20, 0x21, 0x8E,
+			0xDB, 0xC0, 0x73, 0xC7, 0x79, 0xD8, 0xDA, 0xC2,
+			0x66, 0x13, 0x64, 0x34, 0x0C, 0xE1, 0x22, 0x24,
+			0x61, 0x67, 0x08, 0x39, 0x97, 0x3F, 0x33, 0x96,
+			0xF2, 0x44, 0x18, 0x75, 0xBB, 0xF5, 0x6A, 0x5C,
+			0x2C, 0xAE, 0x2A, 0x79, 0x3D, 0x47, 0x19, 0x53,
+			0x50, 0x6C, 0x9F, 0xB3, 0x82, 0x55, 0x09, 0x78,
+			0x7B, 0xAD, 0xBC, 0x05, 0x6F, 0xC8, 0x3D, 0xB6,
+			0x7B, 0x30, 0xE6, 0xBB, 0x8B, 0xD0, 0x2F, 0xA6,
+			0x15, 0xCC, 0x77, 0x8C, 0x21, 0xBA, 0x03, 0xED,
+			0x56, 0x85, 0x82, 0x4F, 0x97, 0x8C, 0x59, 0x4F,
+			0x53, 0x5A, 0xD2, 0x70, 0xD9, 0x07, 0xB3, 0xBD,
+			0x1D, 0x3E, 0x97, 0xD4, 0x7D, 0x93, 0x35, 0xA4,
+			0x82, 0x6E, 0xEA, 0x4B, 0xC8, 0x6C, 0xF5, 0xE6,
+			0xEB, 0xAF, 0x11, 0xB0, 0xB4, 0x71, 0x8F, 0x7B,
+			0xC4, 0x8C, 0xE2, 0x66, 0x51, 0x31, 0x99, 0x01,
+			0x5B, 0xE7, 0x48, 0xF8, 0x4C, 0xE3, 0x9A, 0x77,
+			0xF1, 0xC6, 0x09, 0xDE, 0x76, 0xD4, 0xE3, 0x5C,
+			0xDF, 0xA3, 0xEC, 0x3C, 0x86, 0x7C, 0xA5, 0x3F,
+			0x8D, 0x2A, 0xF3, 0x0B, 0x54, 0xB7, 0x54, 0xA2,
+			0xC1, 0x69, 0xC0, 0x6F, 0x1C, 0x1C, 0x76, 0xD8,
+			0x9F, 0x7A, 0x32, 0xB0, 0xA1, 0xA6, 0x9B, 0xB7,
+			0x21, 0x56, 0x28, 0x2D, 0xB6, 0x97, 0x03, 0x5E,
+			0x65, 0xE3, 0x74, 0x9A, 0x96, 0x7A, 0xF9, 0xF5,
+			0xDD, 0x85, 0xCA, 0x4C, 0xB4, 0x03, 0x6A, 0xCD,
+			0xB6, 0x01, 0xDC, 0x8B, 0xD8, 0x73, 0x8F, 0x4D,
+			0x7F, 0xD6, 0x71, 0xEC, 0xD7, 0xC6, 0x0B, 0x5F,
+			0x09, 0x21, 0xB2, 0x78, 0xA8, 0xAF, 0xAD, 0x2C,
+			0xD4, 0x93, 0x9F, 0x71, 0xF7, 0x05, 0x89, 0x42,
+			0xC9, 0x15, 0x6F, 0x2D, 0xE0, 0xBA, 0xC3, 0xD6,
+			0xBF, 0xAC, 0xF8, 0x24, 0x58, 0x79, 0xA9, 0xC4,
+			0xB4, 0x49, 0x3E, 0x0B, 0x9E, 0x5E, 0xE4, 0xA6,
+			0x8B, 0xE8, 0xDE, 0xFB, 0x4A, 0xF1, 0x69, 0x9D,
+			0x4F, 0x77, 0x83, 0x78, 0x55, 0x19, 0x42, 0x45,
+			0xBF, 0xBD, 0xBD, 0x12, 0x0F, 0xEF, 0x8D, 0x04,
+			0xD8, 0x5C, 0xF2, 0xC9, 0xF1, 0xA6, 0xE0, 0x3E,
+			0x22, 0xA8, 0xA2, 0x5E, 0x66, 0xE9, 0xAB, 0xB4,
+			0x71, 0xBE, 0x4B, 0x3F, 0xBE, 0xC4, 0xBA, 0x4A
+		},
+		.len = 2048
+	},
+	.ciphertext = {
+		.data = {
+			0x5E, 0x86, 0x02, 0x64, 0x32, 0xBF, 0x70, 0xC2,
+			0x19, 0x99, 0x7F, 0x47, 0x0D, 0xA4, 0x91, 0xA8,
+			0x7A, 0xC0, 0xA5, 0x7E, 0xA8, 0x6C, 0x88, 0x00,
+			0xEA, 0xB5, 0x96, 0x6B, 0x25, 0xBD, 0xE7, 0x42,
+			0xDB, 0x35, 0xE7, 0x92, 0x2B, 0x00, 0x82, 0x35,
+			0xD4, 0x2C, 0xCF, 0x47, 0xC8, 0xB2, 0xB3, 0x57,
+			0xF7, 0x24, 0x83, 0x7F, 0xC5, 0x2E, 0xF1, 0xC9,
+			0x57, 0x1A, 0xEF, 0xC2, 0x3A, 0x8C, 0x1E, 0x92,
+			0x88, 0x05, 0xAF, 0x55, 0xE6, 0x0C, 0xA7, 0x6B,
+			0x59, 0x62, 0x32, 0x21, 0xF1, 0xFF, 0xB5, 0x5B,
+			0x22, 0x26, 0x6F, 0x0A, 0x36, 0xDC, 0x0D, 0x16,
+			0x3B, 0x4E, 0x7C, 0xA3, 0x75, 0x30, 0x3F, 0xB0,
+			0x99, 0x38, 0x42, 0x8E, 0x89, 0xA3, 0x7C, 0x99,
+			0x2F, 0x0A, 0xA1, 0xC7, 0xFD, 0x2D, 0x21, 0x8F,
+			0xBD, 0xD4, 0x11, 0xEA, 0x55, 0xF5, 0x6A, 0x50,
+			0x90, 0x3B, 0x60, 0x57, 0xE1, 0x86, 0x1E, 0x50,
+			0x28, 0x67, 0x3F, 0xD2, 0xF3, 0xBD, 0xFA, 0xEE,
+			0xD6, 0x5A, 0x38, 0x30, 0xA3, 0xDD, 0x78, 0xC4,
+			0x37, 0x59, 0x52, 0xC0, 0x92, 0x54, 0xC7, 0x53,
+			0xF0, 0xE6, 0xA9, 0x63, 0x1F, 0x9B, 0x97, 0xFB,
+			0x40, 0x23, 0xFE, 0x52, 0x6A, 0xF0, 0x3A, 0x94,
+			0xEB, 0x6A, 0x9E, 0x8F, 0xC5, 0x05, 0x9C, 0x04,
+			0x1B, 0x00, 0x34, 0x96, 0x12, 0xDA, 0x60, 0xC6,
+			0xAA, 0x1A, 0x3E, 0xEB, 0x70, 0x17, 0x10, 0xBC,
+			0xF5, 0xC2, 0xE2, 0x71, 0xF3, 0xB8, 0x1D, 0xCE,
+			0x47, 0x94, 0x21, 0x71, 0x34, 0x8C, 0xCC, 0xDD,
+			0x27, 0xCE, 0x6F, 0x68, 0xFF, 0x91, 0x4E, 0xC4,
+			0xA0, 0xCA, 0xB0, 0x4F, 0x17, 0x53, 0x73, 0x92,
+			0x6C, 0xA8, 0x16, 0x06, 0xE3, 0xD9, 0x92, 0x99,
+			0xBE, 0xB0, 0x7D, 0x56, 0xF2, 0x72, 0x30, 0xDA,
+			0xC4, 0x4E, 0xF4, 0xA6, 0x8F, 0xD2, 0xC7, 0x8A,
+			0xA2, 0xFC, 0xF5, 0x63, 0x17, 0x48, 0x56, 0x4D,
+			0xBE, 0x94, 0xFE, 0xF5, 0xB1, 0xA9, 0x96, 0xAB,
+			0x3F, 0x2D, 0xD4, 0x15, 0xEE, 0x4F, 0xFA, 0x2C,
+			0xBE, 0x91, 0xB7, 0xBC, 0x18, 0xC8, 0xDB, 0x02,
+			0x20, 0x29, 0xF1, 0xC1, 0x88, 0x8C, 0x8D, 0xD1,
+			0xB3, 0x4E, 0x93, 0x96, 0xDD, 0x22, 0xAB, 0x55,
+			0xB5, 0x9F, 0x8B, 0x20, 0xAE, 0xC6, 0x0E, 0x26,
+			0xC6, 0xFE, 0x2D, 0x5F, 0x95, 0x89, 0x06, 0x15,
+			0x3D, 0x88, 0x16, 0xEC, 0x9B, 0x4A, 0x1B, 0x5D,
+			0x2E, 0xB2, 0x13, 0x56, 0x9F, 0x33, 0xB3, 0x45,
+			0xBF, 0x5F, 0x25, 0x7E, 0x75, 0x22, 0xD2, 0xE6,
+			0x9F, 0xAC, 0x2D, 0xFD, 0x99, 0xC2, 0x9B, 0xFC,
+			0xD7, 0x7A, 0x9B, 0x05, 0x30, 0x0F, 0xB7, 0x4A,
+			0xFE, 0x24, 0xDD, 0x39, 0x9B, 0xBB, 0x2F, 0xDD,
+			0xF9, 0xFB, 0xCA, 0x6C, 0x87, 0xBA, 0x73, 0xD4,
+			0x85, 0x7B, 0xB2, 0x6F, 0x5C, 0xD8, 0xFB, 0xE9,
+			0x41, 0x24, 0x3A, 0x3B, 0x4F, 0x91, 0x77, 0xA2,
+			0x35, 0x78, 0xE5, 0x4C, 0xFE, 0x8B, 0x04, 0x03,
+			0xD3, 0x84, 0xA9, 0x1C, 0xA7, 0x7C, 0x45, 0x13,
+			0x7D, 0xC5, 0x0A, 0x2F, 0x02, 0xF8, 0x56, 0xD5,
+			0x5F, 0x35, 0xED, 0x06, 0xBF, 0x67, 0xBA, 0x51,
+			0x02, 0x95, 0x36, 0xF2, 0x9A, 0xBA, 0x9D, 0xF6,
+			0xD6, 0x77, 0x50, 0xC9, 0xFC, 0x1E, 0x32, 0xB5,
+			0x2F, 0xEA, 0x3C, 0x76, 0xB4, 0xE1, 0xCC, 0x42,
+			0xEB, 0x71, 0x79, 0xD3, 0x7D, 0xB7, 0xC0, 0x88,
+			0x25, 0x81, 0xE8, 0xC0, 0xB8, 0x38, 0x7E, 0x7B,
+			0xFD, 0x18, 0xAB, 0x08, 0xB2, 0x71, 0xA5, 0xAD,
+			0xA7, 0xBE, 0x48, 0x5F, 0x86, 0xE2, 0x41, 0x3D,
+			0x7C, 0x37, 0x7A, 0xAB, 0xDB, 0xE0, 0x3B, 0x3D,
+			0xB6, 0xE8, 0x23, 0x7C, 0xF1, 0x8F, 0xBA, 0xB7,
+			0xE9, 0x78, 0x0B, 0xCA, 0x67, 0xA8, 0x10, 0x36,
+			0xEB, 0x72, 0xED, 0xDD, 0xF0, 0x5C, 0x74, 0x8E,
+			0xE5, 0x2A, 0xAE, 0x6E, 0xC4, 0xF1, 0xFC, 0xD8,
+			0xEE, 0x56, 0x07, 0x88, 0x02, 0xDC, 0x9D, 0xB7,
+			0xF9, 0x13, 0xE1, 0xE1, 0x9D, 0x89, 0x26, 0x0B,
+			0x23, 0x74, 0x4A, 0x43, 0xAA, 0xA0, 0xA8, 0x97,
+			0x85, 0x15, 0x58, 0xAB, 0x2B, 0xB5, 0xDA, 0x1A,
+			0xBA, 0x29, 0x62, 0xCF, 0xDD, 0xA3, 0xBA, 0x9D,
+			0x7D, 0x83, 0xA5, 0x18, 0xD4, 0x03, 0x0F, 0x61,
+			0x9F, 0xB1, 0x7E, 0xEC, 0xD2, 0x6E, 0xAF, 0xCF,
+			0x1E, 0xC1, 0x88, 0x97, 0x99, 0xD6, 0xBF, 0x47,
+			0xB9, 0x0A, 0x69, 0x11, 0x3A, 0x55, 0x8B, 0x1D,
+			0x2D, 0xFF, 0x78, 0xC8, 0xDE, 0x82, 0x29, 0xD6,
+			0x08, 0x3C, 0xC4, 0xCB, 0x2F, 0x01, 0xD0, 0xE8,
+			0xB1, 0x75, 0x5E, 0x23, 0xE0, 0x37, 0x7C, 0x1C,
+			0xB6, 0xD9, 0x47, 0xDE, 0x23, 0x87, 0xD3, 0x68,
+			0x47, 0x46, 0x78, 0xF3, 0xBF, 0x54, 0xA3, 0xB9,
+			0x54, 0xD5, 0xC5, 0x0A, 0x7C, 0x92, 0x2A, 0xC2,
+			0x14, 0x76, 0xA6, 0x5C, 0x6D, 0x0B, 0x94, 0x56,
+			0x00, 0x6B, 0x5C, 0x27, 0xDE, 0x77, 0x9B, 0xF1,
+			0xB1, 0x8C, 0xA7, 0x49, 0x77, 0xFC, 0x4E, 0x29,
+			0x23, 0x8F, 0x2F, 0xF7, 0x83, 0x8D, 0x36, 0xD9,
+			0xAB, 0x0E, 0x78, 0xF5, 0x90, 0x05, 0xB9, 0x79,
+			0x70, 0x88, 0x59, 0x6F, 0xE2, 0xC5, 0xD7, 0x80,
+			0x95, 0x04, 0x29, 0xE0, 0xFA, 0x37, 0xE8, 0x8B,
+			0xC5, 0x21, 0x51, 0x1A, 0x62, 0xCE, 0x93, 0xAF,
+			0x1A, 0xFE, 0xC3, 0x6F, 0x86, 0x94, 0x5E, 0x13,
+			0xA6, 0x9A, 0x26, 0xF0, 0xB5, 0x7C, 0x41, 0x9A,
+			0x80, 0xB8, 0x84, 0x5A, 0x55, 0xA9, 0xB0, 0x6A,
+			0xFA, 0xEB, 0x46, 0x32, 0x0B, 0xE2, 0x9C, 0x65,
+			0x86, 0x11, 0x39, 0x7E, 0xAF, 0x93, 0x19, 0x09,
+			0x70, 0x40, 0x80, 0x14, 0xBA, 0x1D, 0xB3, 0x62,
+			0x5B, 0xF3, 0x9A, 0x21, 0x98, 0x7E, 0x63, 0xB6,
+			0x1A, 0xBD, 0x65, 0x98, 0x35, 0x2A, 0xA9, 0x76,
+			0x29, 0x59, 0x84, 0x25, 0x81, 0xB8, 0xDE, 0x25,
+			0x32, 0x10, 0x50, 0xB7, 0xD3, 0xB3, 0x69, 0xC8,
+			0xE1, 0x33, 0xCB, 0x9E, 0x9C, 0x7A, 0x7C, 0xD2,
+			0x6C, 0x92, 0x97, 0xA9, 0xFA, 0xAF, 0x30, 0xBA,
+			0x9A, 0xB3, 0x3D, 0x9A, 0xE5, 0x0A, 0x9B, 0x8D,
+			0x89, 0xE2, 0x2B, 0xB8, 0xBC, 0xF0, 0x23, 0xFF,
+			0x7B, 0x0D, 0x00, 0x36, 0xEE, 0x79, 0xCB, 0xA5,
+			0x70, 0x4C, 0x66, 0x02, 0x79, 0x2E, 0x5B, 0x83,
+			0xCE, 0x55, 0x8B, 0x89, 0xD6, 0xE3, 0x71, 0x63,
+			0xBC, 0xB1, 0x5F, 0x67, 0xB4, 0x7E, 0x05, 0x0D,
+			0xAC, 0x6D, 0x4E, 0x2C, 0xA5, 0xF4, 0x47, 0x89,
+			0xAC, 0x5E, 0xBE, 0x2F, 0xFC, 0x9B, 0x2F, 0x0B,
+			0xBE, 0x63, 0x54, 0x97, 0xBB, 0x23, 0x27, 0xCD,
+			0xB9, 0xB2, 0x28, 0x0D, 0xA4, 0x78, 0x2C, 0xAB,
+			0xD1, 0xC9, 0x94, 0x40, 0x54, 0xF2, 0x35, 0x61,
+			0x49, 0x01, 0x87, 0x55, 0xA5, 0xB5, 0x1E, 0x84,
+			0x92, 0x9E, 0xC1, 0xA4, 0x0B, 0x66, 0x2B, 0xF8,
+			0xAF, 0xC3, 0x1E, 0xAF, 0x66, 0x3F, 0x6F, 0x5F,
+			0x70, 0xEC, 0x25, 0x29, 0xE4, 0x65, 0xB2, 0x04,
+			0x47, 0xF6, 0x3C, 0xB5, 0x5F, 0x66, 0x9F, 0xA4,
+			0x1B, 0xFC, 0xA2, 0xD5, 0x3E, 0x84, 0xBA, 0x88,
+			0x0D, 0xF1, 0x6A, 0xF2, 0xF6, 0x1D, 0xF1, 0xA3,
+			0x45, 0xB2, 0x51, 0xD8, 0xA2, 0x8F, 0x55, 0xA6,
+			0x89, 0xC4, 0x15, 0xD5, 0x73, 0xA8, 0xB1, 0x31,
+			0x66, 0x9E, 0xC1, 0x43, 0xE1, 0x5D, 0x4E, 0x04,
+			0x84, 0x8F, 0xF2, 0xBC, 0xE1, 0x4E, 0x4D, 0x60,
+			0x81, 0xCA, 0x53, 0x34, 0x95, 0x17, 0x3B, 0xAE,
+			0x8F, 0x95, 0xA7, 0xC6, 0x47, 0xC6, 0xAC, 0x32,
+			0x12, 0x39, 0xCA, 0xEF, 0xE0, 0x07, 0xBF, 0x17,
+			0x4F, 0xDC, 0x1B, 0x4E, 0x3C, 0x84, 0xF1, 0x9F,
+			0x43, 0x70, 0x19, 0xE6, 0xF3, 0x8B, 0x8B, 0x5D,
+			0xDB, 0xD2, 0x9D, 0xD4, 0xB2, 0x30, 0x45, 0x55,
+			0xA2, 0x67, 0xA2, 0x76, 0x4A, 0x74, 0xAD, 0x88,
+			0x71, 0xE6, 0x3E, 0x13, 0x06, 0x30, 0x17, 0xE1,
+			0xEF, 0xAC, 0x71, 0xFB, 0x43, 0xCD, 0xF6, 0xFA,
+			0x0E, 0x4C, 0x4E, 0x16, 0xF6, 0x6A, 0x09, 0x86,
+			0x6B, 0xEA, 0x47, 0x6C, 0x70, 0xE7, 0xAD, 0xA2,
+			0xE0, 0xFD, 0x7F, 0xF0, 0x5C, 0x21, 0x53, 0x0F,
+			0x28, 0xA1, 0x43, 0xE1, 0x06, 0xCA, 0x0B, 0x31,
+			0x88, 0x22, 0xA6, 0xE6, 0x34, 0x5B, 0xE6, 0xCF,
+			0x25, 0x81, 0x63, 0xFF, 0x78, 0x66, 0x85, 0x19,
+			0xE2, 0x0A, 0x7E, 0x81, 0x8A, 0x17, 0x1A, 0x18,
+			0x8A, 0x5F, 0x5D, 0x9E, 0x82, 0x13, 0x10, 0xB9,
+			0xD3, 0xE6, 0x93, 0x1C, 0xE4, 0x2C, 0xCB, 0x49,
+			0x1E, 0xB6, 0x36, 0x13, 0xBF, 0x28, 0xEE, 0xCC,
+			0x49, 0xF5, 0x79, 0xFC, 0x20, 0x65, 0xBD, 0xE8,
+			0xF0, 0x1B, 0x4E, 0xC0, 0x0D, 0x3E, 0x89, 0x91,
+			0xCC, 0x64, 0x10, 0xC0, 0x2A, 0x2B, 0xA3, 0xFA,
+			0x60, 0x3D, 0xC3, 0x52, 0x2F, 0x93, 0xDE, 0xB7,
+			0x6E, 0x8A, 0xDF, 0x6C, 0x08, 0xCC, 0x8B, 0x3B,
+			0xC8, 0x50, 0xEF, 0x58, 0x64, 0x9A, 0x3D, 0x16,
+			0x70, 0x94, 0x11, 0xD8, 0x94, 0x2B, 0x70, 0x91,
+			0x10, 0x70, 0x88, 0xF0, 0x40, 0x75, 0x9A, 0x2B,
+			0x39, 0xA1, 0x27, 0x3F, 0x2E, 0x91, 0xEA, 0xA1,
+			0xCC, 0x12, 0xC1, 0x7F, 0x73, 0x8C, 0x5C, 0x6B,
+			0xFC, 0xC5, 0x6A, 0x1C, 0x05, 0xF1, 0x3D, 0x30,
+			0x82, 0x4A, 0x65, 0x35, 0xCE, 0x80, 0x10, 0xBB,
+			0x41, 0x94, 0xFB, 0x84, 0x80, 0x7B, 0x91, 0xC4,
+			0x4D, 0xA3, 0x5F, 0xB9, 0xFB, 0xF9, 0xC9, 0x1D,
+			0x4F, 0x99, 0x1C, 0x1F, 0x47, 0x44, 0x89, 0x0E,
+			0xED, 0x6D, 0xB5, 0x85, 0x41, 0x94, 0xEF, 0xF9,
+			0x2E, 0xA0, 0xC8, 0xCA, 0xFB, 0x44, 0x02, 0xC6,
+			0xBF, 0x96, 0x87, 0x80, 0x1D, 0xEF, 0x2A, 0x81,
+			0xAB, 0xB2, 0x56, 0xDF, 0x54, 0x8B, 0xAB, 0xAF,
+			0xFE, 0x18, 0x8C, 0xAA, 0xD4, 0x00, 0x17, 0xBE,
+			0xCF, 0x06, 0xE5, 0xA6, 0xBF, 0x5A, 0x52, 0x3B,
+			0x4E, 0xF5, 0x65, 0x60, 0x95, 0xDE, 0x8A, 0x25,
+			0x88, 0xA5, 0x24, 0x96, 0x29, 0x13, 0x0D, 0x19,
+			0x45, 0x95, 0x91, 0x08, 0xD2, 0x9C, 0x4C, 0x34,
+			0x42, 0xF0, 0xA5, 0x72, 0xEB, 0xFB, 0x5E, 0xAA,
+			0x68, 0x80, 0x82, 0xAC, 0x34, 0xAD, 0x89, 0xF6,
+			0xAF, 0x54, 0x82, 0xCF, 0x98, 0x8C, 0x75, 0x63,
+			0x8D, 0xBD, 0x1C, 0x2A, 0xD7, 0x00, 0xA7, 0x8E,
+			0xB9, 0x33, 0xB6, 0x3B, 0x95, 0x9A, 0x59, 0x1D,
+			0x3F, 0x23, 0x6B, 0x18, 0xF8, 0x4F, 0x1A, 0x8D,
+			0xC0, 0x26, 0x9F, 0x87, 0x61, 0xB6, 0xC6, 0x60,
+			0x38, 0x22, 0x73, 0x1C, 0x99, 0x23, 0xEF, 0xD9,
+			0xFD, 0xCB, 0x54, 0x74, 0xBB, 0x77, 0x14, 0xA3,
+			0xA9, 0xE6, 0x7C, 0x7E, 0x03, 0x3A, 0x13, 0x6E,
+			0x1D, 0x6F, 0x64, 0xB3, 0xFA, 0xFB, 0x52, 0xDE,
+			0xDF, 0x08, 0xFB, 0x6F, 0xC5, 0xFA, 0x51, 0x6A,
+			0x69, 0x29, 0x9B, 0x96, 0xE8, 0x16, 0xC8, 0xD1,
+			0xE4, 0x19, 0xBD, 0x14, 0x74, 0x27, 0xE7, 0x10,
+			0xF0, 0xC3, 0xE2, 0xA7, 0x60, 0x48, 0xBF, 0xDD,
+			0xC4, 0x0D, 0xD0, 0xF2, 0xEF, 0xA6, 0xC9, 0xA2,
+			0x73, 0xD1, 0xCF, 0x41, 0xE1, 0x3B, 0xE5, 0x49,
+			0x91, 0x5D, 0x09, 0xFD, 0x1D, 0x95, 0x29, 0xDB,
+			0x52, 0x48, 0xEB, 0xF5, 0x1D, 0xF8, 0x06, 0x67,
+			0x75, 0xF2, 0x57, 0xA4, 0x20, 0x60, 0xEA, 0xB0,
+			0x85, 0x93, 0x7C, 0xDD, 0x52, 0x01, 0xD4, 0x57,
+			0xA8, 0x31, 0x2D, 0xF9, 0x0A, 0xD2, 0x2A, 0xD1,
+			0x34, 0x18, 0x35, 0x16, 0xB6, 0x8B, 0x0F, 0x0B,
+			0xCF, 0x50, 0x80, 0xFE, 0x76, 0xCC, 0x4F, 0x30,
+			0x98, 0x19, 0x16, 0x3D, 0x01, 0xEA, 0x8D, 0x8A,
+			0x3D, 0xDC, 0xFB, 0x1F, 0x77, 0x8D, 0x72, 0x76,
+			0x02, 0x3C, 0x5D, 0xEE, 0x55, 0x13, 0x5B, 0x6E,
+			0x5A, 0x2D, 0xD5, 0x77, 0xD7, 0x01, 0x84, 0x7D,
+			0x21, 0x8C, 0xDD, 0x94, 0x7D, 0x31, 0x3D, 0xF0,
+			0xE7, 0x28, 0xF5, 0x72, 0x36, 0x60, 0xE0, 0x59,
+			0x5F, 0xFE, 0x38, 0xF8, 0x2F, 0xDB, 0x9E, 0x55,
+			0x5A, 0xD6, 0xBA, 0x6C, 0x87, 0xF3, 0xC0, 0x76,
+			0x5F, 0xA3, 0x0A, 0xC3, 0xA3, 0x8D, 0x0E, 0x52,
+			0xA8, 0xDA, 0x26, 0x3A, 0xF9, 0x3E, 0x36, 0xB1,
+			0x06, 0xF8, 0x20, 0x2D, 0x1C, 0x0B, 0x93, 0xBB,
+			0xD3, 0x64, 0x77, 0xCE, 0x11, 0xFC, 0xA2, 0x0E,
+			0x1B, 0x5B, 0x9E, 0x13, 0x9F, 0x20, 0x8B, 0xAA,
+			0xCD, 0x72, 0xD7, 0xA6, 0xF3, 0x1E, 0x4F, 0x72,
+			0xC6, 0x49, 0x0F, 0x7B, 0xF0, 0x4C, 0x61, 0x1F,
+			0x43, 0x0D, 0x4F, 0x0D, 0x33, 0x13, 0xED, 0x63,
+			0xE5, 0xDB, 0x71, 0xAB, 0xA4, 0x83, 0xEF, 0xDC,
+			0x86, 0x9D, 0x4B, 0xBD, 0x1B, 0x8A, 0xFE, 0x39,
+			0xA8, 0x8B, 0xBA, 0x4C, 0x85, 0x28, 0xFC, 0xB3,
+			0x62, 0x85, 0xD2, 0xF0, 0x38, 0xD0, 0x4B, 0xA4,
+			0xD1, 0x3B, 0xD4, 0xD0, 0x2C, 0x78, 0x6C, 0x6A,
+			0xC2, 0x64, 0x2C, 0x31, 0x4A, 0xD8, 0x69, 0x24,
+			0xED, 0x77, 0x7D, 0x68, 0x9A, 0xA1, 0x78, 0x81,
+			0xD9, 0x7E, 0x6C, 0xFE, 0x0A, 0x0D, 0x76, 0xF7,
+			0x4B, 0x58, 0xE7, 0xC9, 0xB5, 0x11, 0x07, 0x87,
+			0x88, 0x6A, 0x9F, 0x3D, 0xE0, 0xEE, 0xCC, 0x60,
+			0x6B, 0x6B, 0xE6, 0xB5, 0x54, 0x8B, 0x32, 0x1F,
+			0x04, 0x1D, 0x0E, 0x9E, 0xFA, 0x6D, 0xB0, 0xE0,
+			0x6D, 0xF9, 0x79, 0xB4, 0xAB, 0x5E, 0xDF, 0x23,
+			0x7F, 0x95, 0xAD, 0x80, 0x17, 0x23, 0x90, 0x1F,
+			0xF0, 0xC3, 0xD9, 0x2D, 0xAC, 0x3F, 0x63, 0xF5,
+			0x77, 0xC5, 0x05, 0xAC, 0x06, 0xB6, 0xA1, 0xB4,
+			0xA2, 0x40, 0xB3, 0x99, 0x34, 0x7D, 0x31, 0xD4,
+			0xB1, 0xD4, 0xC1, 0xBB, 0x71, 0x1E, 0xDA, 0x3F,
+			0xA9, 0x12, 0x68, 0xFA, 0x5B, 0x20, 0x24, 0x6D,
+			0x4D, 0x72, 0x43, 0x18, 0xBF, 0x66, 0x71, 0x69,
+			0x26, 0x7D, 0x77, 0x78, 0xF8, 0xE5, 0x20, 0xAE,
+			0x56, 0x6C, 0x0F, 0x72, 0x94, 0x42, 0x85, 0x4F,
+			0xE4, 0xFB, 0x32, 0x26, 0x1B, 0x1C, 0x6E, 0x0B,
+			0xF0, 0xB8, 0x58, 0x00, 0xD2, 0x36, 0x64, 0xAD,
+			0xA9, 0x00, 0xCE, 0x35, 0x3C, 0x88, 0x79, 0x94,
+			0x0C, 0x0C, 0x9B, 0xF2, 0xDA, 0xBD, 0xCA, 0x93,
+			0x37, 0x26, 0xD3, 0x08, 0x54, 0xD2, 0x0D, 0xBC,
+			0x5D, 0x43, 0x5F, 0xCF, 0x28, 0xB5, 0xAA, 0x15,
+			0x28, 0x46, 0x45, 0x6B, 0xE8, 0xDF, 0xE8, 0xCE,
+			0x8F, 0xC0, 0x1A, 0x53, 0x63, 0x3B, 0x53, 0x75,
+			0xDD, 0x43, 0x1F, 0x07, 0x0A, 0xD5, 0xA1, 0x2A,
+			0x6E, 0x28, 0xE1, 0xD7, 0xD0, 0x09, 0xCF, 0x62,
+			0xC1, 0x5F, 0x21, 0xDB, 0xC5, 0x40, 0x99, 0x48,
+			0x87, 0x6E, 0x11, 0xF5, 0x5A, 0x4E, 0xBC, 0xF9,
+			0xA8, 0x02, 0x7C, 0x47, 0x39, 0xA5, 0xD8, 0x52,
+			0xB1, 0x80, 0xDC, 0xFE, 0x08, 0x4B, 0x5D, 0x09,
+			0xDE, 0x06, 0xF3, 0x2A, 0xAD, 0x14, 0x76, 0x40,
+			0x2F, 0x82, 0x28, 0x6A, 0xB6, 0x43, 0xEF, 0x71,
+			0x63, 0xC2, 0x56, 0xEB, 0x3B, 0x4B, 0x52, 0x2F,
+			0x93, 0xD3, 0x18, 0x3E, 0x18, 0xA8, 0xF7, 0x58,
+			0xFC, 0x8B, 0x3D, 0x4D, 0x4B, 0x72, 0xBD, 0xF7,
+			0x04, 0xC9, 0xB8, 0xD7, 0x6C, 0x8C, 0x67, 0xBB,
+			0x4C, 0x9B, 0x57, 0xF7, 0x22, 0x4E, 0x41, 0xB6,
+			0xFD, 0xD9, 0xF8, 0x41, 0x62, 0x0F, 0xFF, 0xAA,
+			0xC6, 0x87, 0x95, 0xFF, 0xFD, 0x58, 0xD9, 0xB2,
+			0xBA, 0x47, 0x61, 0x24, 0xEA, 0x92, 0x6E, 0x74,
+			0xB3, 0xDA, 0xE5, 0x83, 0x99, 0x24, 0xB1, 0x71,
+			0x2A, 0x33, 0xB2, 0xD5, 0x8F, 0xF0, 0x32, 0xCE,
+			0x37, 0xCF, 0xC7, 0x1C, 0xE8, 0xDE, 0x46, 0x78,
+			0x96, 0x97, 0xF6, 0x73, 0x90, 0xE5, 0x71, 0x05,
+			0xEA, 0x0D, 0xC2, 0x1D, 0x9E, 0x43, 0x34, 0xBC,
+			0x8F, 0x45, 0xE5, 0x08, 0xCA, 0x20, 0x0C, 0x84
+		},
+		.len = 2048
+	},
+	.auth_tag = {
+		.data = {
+			0xD0, 0x62, 0x1F, 0x20, 0x1C, 0xE8, 0xDD, 0x36,
+			0x00, 0x74, 0xF6, 0xD7, 0xFD, 0x2C, 0xA0, 0xAF
+		},
+		.len = 16
+	}
+};
+
 /** GMAC Test Vectors */
 static uint8_t gmac_plaintext[GMAC_LARGE_PLAINTEXT_LENGTH] = {
 			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4 2/3] crypto: add sgl support in openssl PMD
From: Tomasz Kulasek @ 2017-01-05 16:46 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch
In-Reply-To: <1483634768-35012-1-git-send-email-tomaszx.kulasek@intel.com>


Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 doc/guides/cryptodevs/openssl.rst        |    3 +-
 drivers/crypto/openssl/rte_openssl_pmd.c |  329 +++++++++++++++++++++++-------
 2 files changed, 259 insertions(+), 73 deletions(-)

diff --git a/doc/guides/cryptodevs/openssl.rst b/doc/guides/cryptodevs/openssl.rst
index d2b5906..d0b1eeb 100644
--- a/doc/guides/cryptodevs/openssl.rst
+++ b/doc/guides/cryptodevs/openssl.rst
@@ -112,6 +112,7 @@ Limitations
 -----------
 
 * Maximum number of sessions is 2048.
-* Chained mbufs are not supported.
+* Chained mbufs are supported only for source mbuf (destination must be
+  contiguous).
 * Hash only is not supported for GCM and GMAC.
 * Cipher only is not supported for GCM and GMAC.
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index 832ea1d..e466c79 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -484,24 +484,112 @@
  * Process Operations
  *------------------------------------------------------------------------------
  */
+static inline int
+process_openssl_encryption_update(struct rte_mbuf *mbuf_src, int offset,
+		uint8_t **dst, int srclen, EVP_CIPHER_CTX *ctx)
+{
+	struct rte_mbuf *m;
+	int dstlen;
+	int l, n = srclen;
+	uint8_t *src;
+
+	for (m = mbuf_src; m != NULL && offset > rte_pktmbuf_data_len(m);
+			m = m->next)
+		offset -= rte_pktmbuf_data_len(m);
+
+	if (m == 0)
+		return -1;
+
+	src = rte_pktmbuf_mtod_offset(m, uint8_t *, offset);
+
+	l = rte_pktmbuf_data_len(m) - offset;
+	if (srclen <= l) {
+		if (EVP_EncryptUpdate(ctx, *dst, &dstlen, src, srclen) <= 0)
+			return -1;
+		*dst += l;
+		return 0;
+	}
+
+	if (EVP_EncryptUpdate(ctx, *dst, &dstlen, src, l) <= 0)
+		return -1;
+
+	*dst += dstlen;
+	n -= l;
+
+	for (m = m->next; (m != NULL) && (n > 0); m = m->next) {
+		src = rte_pktmbuf_mtod(m, uint8_t *);
+		l = rte_pktmbuf_data_len(m) < n ? rte_pktmbuf_data_len(m) : n;
+		if (EVP_EncryptUpdate(ctx, *dst, &dstlen, src, l) <= 0)
+			return -1;
+		*dst += dstlen;
+		n -= l;
+	}
+
+	return 0;
+}
+
+static inline int
+process_openssl_decryption_update(struct rte_mbuf *mbuf_src, int offset,
+		uint8_t **dst, int srclen, EVP_CIPHER_CTX *ctx)
+{
+	struct rte_mbuf *m;
+	int dstlen;
+	int l, n = srclen;
+	uint8_t *src;
+
+	for (m = mbuf_src; m != NULL && offset > rte_pktmbuf_data_len(m);
+			m = m->next)
+		offset -= rte_pktmbuf_data_len(m);
+
+	if (m == 0)
+		return -1;
+
+	src = rte_pktmbuf_mtod_offset(m, uint8_t *, offset);
+
+	l = rte_pktmbuf_data_len(m) - offset;
+	if (srclen <= l) {
+		if (EVP_DecryptUpdate(ctx, *dst, &dstlen, src, srclen) <= 0)
+			return -1;
+		*dst += l;
+		return 0;
+	}
+
+	if (EVP_DecryptUpdate(ctx, *dst, &dstlen, src, l) <= 0)
+		return -1;
+
+	*dst += dstlen;
+	n -= l;
+
+	for (m = m->next; (m != NULL) && (n > 0); m = m->next) {
+		src = rte_pktmbuf_mtod(m, uint8_t *);
+		l = rte_pktmbuf_data_len(m) < n ? rte_pktmbuf_data_len(m) : n;
+		if (EVP_DecryptUpdate(ctx, *dst, &dstlen, src, l) <= 0)
+			return -1;
+		*dst += dstlen;
+		n -= l;
+	}
+
+	return 0;
+}
 
 /** Process standard openssl cipher encryption */
 static int
-process_openssl_cipher_encrypt(uint8_t *src, uint8_t *dst,
-		uint8_t *iv, uint8_t *key, int srclen,
+process_openssl_cipher_encrypt(struct rte_mbuf *mbuf_src, uint8_t *dst,
+		int offset, uint8_t *iv, uint8_t *key, int srclen,
 		EVP_CIPHER_CTX *ctx, const EVP_CIPHER *algo)
 {
-	int dstlen, totlen;
+	int totlen;
 
 	if (EVP_EncryptInit_ex(ctx, algo, NULL, key, iv) <= 0)
 		goto process_cipher_encrypt_err;
 
 	EVP_CIPHER_CTX_set_padding(ctx, 0);
 
-	if (EVP_EncryptUpdate(ctx, dst, &dstlen, src, srclen) <= 0)
+	if (process_openssl_encryption_update(mbuf_src, offset, &dst,
+			srclen, ctx))
 		goto process_cipher_encrypt_err;
 
-	if (EVP_EncryptFinal_ex(ctx, dst + dstlen, &totlen) <= 0)
+	if (EVP_EncryptFinal_ex(ctx, dst, &totlen) <= 0)
 		goto process_cipher_encrypt_err;
 
 	return 0;
@@ -513,11 +601,11 @@
 
 /** Process standard openssl cipher decryption */
 static int
-process_openssl_cipher_decrypt(uint8_t *src, uint8_t *dst,
-		uint8_t *iv, uint8_t *key, int srclen,
+process_openssl_cipher_decrypt(struct rte_mbuf *mbuf_src, uint8_t *dst,
+		int offset, uint8_t *iv, uint8_t *key, int srclen,
 		EVP_CIPHER_CTX *ctx, const EVP_CIPHER *algo)
 {
-	int dstlen, totlen;
+	int totlen;
 
 	if (EVP_DecryptInit_ex(ctx, algo, NULL, key, iv) <= 0)
 		goto process_cipher_decrypt_err;
@@ -525,12 +613,12 @@
 	if (EVP_CIPHER_CTX_set_padding(ctx, 0) <= 0)
 		goto process_cipher_decrypt_err;
 
-	if (EVP_DecryptUpdate(ctx, dst, &dstlen, src, srclen) <= 0)
+	if (process_openssl_decryption_update(mbuf_src, offset, &dst,
+			srclen, ctx))
 		goto process_cipher_decrypt_err;
 
-	if (EVP_DecryptFinal_ex(ctx, dst + dstlen, &totlen) <= 0)
+	if (EVP_DecryptFinal_ex(ctx, dst, &totlen) <= 0)
 		goto process_cipher_decrypt_err;
-
 	return 0;
 
 process_cipher_decrypt_err:
@@ -540,11 +628,25 @@
 
 /** Process cipher des 3 ctr encryption, decryption algorithm */
 static int
-process_openssl_cipher_des3ctr(uint8_t *src, uint8_t *dst,
-		uint8_t *iv, uint8_t *key, int srclen, EVP_CIPHER_CTX *ctx)
+process_openssl_cipher_des3ctr(struct rte_mbuf *mbuf_src, uint8_t *dst,
+		int offset, uint8_t *iv, uint8_t *key, int srclen,
+		EVP_CIPHER_CTX *ctx)
 {
 	uint8_t ebuf[8], ctr[8];
 	int unused, n;
+	struct rte_mbuf *m;
+	uint8_t *src;
+	int l;
+
+	for (m = mbuf_src; m != NULL && offset > rte_pktmbuf_data_len(m);
+			m = m->next)
+		offset -= rte_pktmbuf_data_len(m);
+
+	if (m == 0)
+		goto process_cipher_des3ctr_err;
+
+	src = rte_pktmbuf_mtod_offset(m, uint8_t *, offset);
+	l = rte_pktmbuf_data_len(m) - offset;
 
 	/* We use 3DES encryption also for decryption.
 	 * IV is not important for 3DES ecb
@@ -553,9 +655,8 @@
 		goto process_cipher_des3ctr_err;
 
 	memcpy(ctr, iv, 8);
-	n = 0;
 
-	while (n < srclen) {
+	for (n = 0; n < srclen; n++) {
 		if (n % 8 == 0) {
 			if (EVP_EncryptUpdate(ctx,
 					(unsigned char *)&ebuf, &unused,
@@ -563,8 +664,16 @@
 				goto process_cipher_des3ctr_err;
 			ctr_inc(ctr);
 		}
-		dst[n] = src[n] ^ ebuf[n % 8];
-		n++;
+		dst[n] = *(src++) ^ ebuf[n % 8];
+
+		l--;
+		if (!l) {
+			m = m->next;
+			if (m) {
+				src = rte_pktmbuf_mtod(m, uint8_t *);
+				l = rte_pktmbuf_data_len(m);
+			}
+		}
 	}
 
 	return 0;
@@ -576,9 +685,9 @@
 
 /** Process auth/encription aes-gcm algorithm */
 static int
-process_openssl_auth_encryption_gcm(uint8_t *src, int srclen,
-		uint8_t *aad, int aadlen, uint8_t *iv, int ivlen,
-		uint8_t *key, uint8_t *dst,	uint8_t *tag,
+process_openssl_auth_encryption_gcm(struct rte_mbuf *mbuf_src, int offset,
+		int srclen, uint8_t *aad, int aadlen, uint8_t *iv, int ivlen,
+		uint8_t *key, uint8_t *dst, uint8_t *tag,
 		EVP_CIPHER_CTX *ctx, const EVP_CIPHER *algo)
 {
 	int len = 0, unused = 0;
@@ -593,20 +702,20 @@
 	if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv) <= 0)
 		goto process_auth_encryption_gcm_err;
 
-	if (aadlen > 0) {
+	if (aadlen > 0)
 		if (EVP_EncryptUpdate(ctx, NULL, &len, aad, aadlen) <= 0)
 			goto process_auth_encryption_gcm_err;
 
-		/* Workaround open ssl bug in version less then 1.0.1f */
-		if (EVP_EncryptUpdate(ctx, empty, &unused, empty, 0) <= 0)
-			goto process_auth_encryption_gcm_err;
-	}
-
 	if (srclen > 0)
-		if (EVP_EncryptUpdate(ctx, dst, &len, src, srclen) <= 0)
+		if (process_openssl_encryption_update(mbuf_src, offset, &dst,
+				srclen, ctx))
 			goto process_auth_encryption_gcm_err;
 
-	if (EVP_EncryptFinal_ex(ctx, dst + len, &len) <= 0)
+	/* Workaround open ssl bug in version less then 1.0.1f */
+	if (EVP_EncryptUpdate(ctx, empty, &unused, empty, 0) <= 0)
+		goto process_auth_encryption_gcm_err;
+
+	if (EVP_EncryptFinal_ex(ctx, dst, &len) <= 0)
 		goto process_auth_encryption_gcm_err;
 
 	if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag) <= 0)
@@ -620,10 +729,10 @@
 }
 
 static int
-process_openssl_auth_decryption_gcm(uint8_t *src, int srclen,
-		uint8_t *aad, int aadlen, uint8_t *iv, int ivlen,
-		uint8_t *key, uint8_t *dst, uint8_t *tag,
-		EVP_CIPHER_CTX *ctx, const EVP_CIPHER *algo)
+process_openssl_auth_decryption_gcm(struct rte_mbuf *mbuf_src, int offset,
+		int srclen, uint8_t *aad, int aadlen, uint8_t *iv, int ivlen,
+		uint8_t *key, uint8_t *dst, uint8_t *tag, EVP_CIPHER_CTX *ctx,
+		const EVP_CIPHER *algo)
 {
 	int len = 0, unused = 0;
 	uint8_t empty[] = {};
@@ -640,20 +749,20 @@
 	if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv) <= 0)
 		goto process_auth_decryption_gcm_err;
 
-	if (aadlen > 0) {
+	if (aadlen > 0)
 		if (EVP_DecryptUpdate(ctx, NULL, &len, aad, aadlen) <= 0)
 			goto process_auth_decryption_gcm_err;
 
-		/* Workaround open ssl bug in version less then 1.0.1f */
-		if (EVP_DecryptUpdate(ctx, empty, &unused, empty, 0) <= 0)
-			goto process_auth_decryption_gcm_err;
-	}
-
 	if (srclen > 0)
-		if (EVP_DecryptUpdate(ctx, dst, &len, src, srclen) <= 0)
+		if (process_openssl_decryption_update(mbuf_src, offset, &dst,
+				srclen, ctx))
 			goto process_auth_decryption_gcm_err;
 
-	if (EVP_DecryptFinal_ex(ctx, dst + len, &len) <= 0)
+	/* Workaround open ssl bug in version less then 1.0.1f */
+	if (EVP_DecryptUpdate(ctx, empty, &unused, empty, 0) <= 0)
+		goto process_auth_decryption_gcm_err;
+
+	if (EVP_DecryptFinal_ex(ctx, dst, &len) <= 0)
 		goto process_auth_decryption_gcm_final_err;
 
 	return 0;
@@ -668,21 +777,50 @@
 
 /** Process standard openssl auth algorithms */
 static int
-process_openssl_auth(uint8_t *src, uint8_t *dst,
+process_openssl_auth(struct rte_mbuf *mbuf_src, uint8_t *dst, int offset,
 		__rte_unused uint8_t *iv, __rte_unused EVP_PKEY * pkey,
 		int srclen, EVP_MD_CTX *ctx, const EVP_MD *algo)
 {
 	size_t dstlen;
+	struct rte_mbuf *m;
+	int l, n = srclen;
+	uint8_t *src;
+
+	for (m = mbuf_src; m != NULL && offset > rte_pktmbuf_data_len(m);
+			m = m->next)
+		offset -= rte_pktmbuf_data_len(m);
+
+	if (m == 0)
+		goto process_auth_err;
 
 	if (EVP_DigestInit_ex(ctx, algo, NULL) <= 0)
 		goto process_auth_err;
 
-	if (EVP_DigestUpdate(ctx, (char *)src, srclen) <= 0)
+	src = rte_pktmbuf_mtod_offset(m, uint8_t *, offset);
+
+	l = rte_pktmbuf_data_len(m) - offset;
+	if (srclen <= l) {
+		if (EVP_DigestUpdate(ctx, (char *)src, srclen) <= 0)
+			goto process_auth_err;
+		goto process_auth_final;
+	}
+
+	if (EVP_DigestUpdate(ctx, (char *)src, l) <= 0)
 		goto process_auth_err;
 
+	n -= l;
+
+	for (m = m->next; (m != NULL) && (n > 0); m = m->next) {
+		src = rte_pktmbuf_mtod(m, uint8_t *);
+		l = rte_pktmbuf_data_len(m) < n ? rte_pktmbuf_data_len(m) : n;
+		if (EVP_DigestUpdate(ctx, (char *)src, l) <= 0)
+			goto process_auth_err;
+		n -= l;
+	}
+
+process_auth_final:
 	if (EVP_DigestFinal_ex(ctx, dst, (unsigned int *)&dstlen) <= 0)
 		goto process_auth_err;
-
 	return 0;
 
 process_auth_err:
@@ -692,18 +830,48 @@
 
 /** Process standard openssl auth algorithms with hmac */
 static int
-process_openssl_auth_hmac(uint8_t *src, uint8_t *dst,
+process_openssl_auth_hmac(struct rte_mbuf *mbuf_src, uint8_t *dst, int offset,
 		__rte_unused uint8_t *iv, EVP_PKEY *pkey,
-		int srclen,	EVP_MD_CTX *ctx, const EVP_MD *algo)
+		int srclen, EVP_MD_CTX *ctx, const EVP_MD *algo)
 {
 	size_t dstlen;
+	struct rte_mbuf *m;
+	int l, n = srclen;
+	uint8_t *src;
+
+	for (m = mbuf_src; m != NULL && offset > rte_pktmbuf_data_len(m);
+			m = m->next)
+		offset -= rte_pktmbuf_data_len(m);
+
+	if (m == 0)
+		goto process_auth_err;
 
 	if (EVP_DigestSignInit(ctx, NULL, algo, NULL, pkey) <= 0)
 		goto process_auth_err;
 
-	if (EVP_DigestSignUpdate(ctx, (char *)src, srclen) <= 0)
+	src = rte_pktmbuf_mtod_offset(m, uint8_t *, offset);
+
+	l = rte_pktmbuf_data_len(m) - offset;
+	if (srclen <= l) {
+		if (EVP_DigestSignUpdate(ctx, (char *)src, srclen) <= 0)
+			goto process_auth_err;
+		goto process_auth_final;
+	}
+
+	if (EVP_DigestSignUpdate(ctx, (char *)src, l) <= 0)
 		goto process_auth_err;
 
+	n -= l;
+
+	for (m = m->next; (m != NULL) && (n > 0); m = m->next) {
+		src = rte_pktmbuf_mtod(m, uint8_t *);
+		l = rte_pktmbuf_data_len(m) < n ? rte_pktmbuf_data_len(m) : n;
+		if (EVP_DigestSignUpdate(ctx, (char *)src, l) <= 0)
+			goto process_auth_err;
+		n -= l;
+	}
+
+process_auth_final:
 	if (EVP_DigestSignFinal(ctx, dst, &dstlen) <= 0)
 		goto process_auth_err;
 
@@ -723,9 +891,18 @@
 		struct rte_mbuf *mbuf_src, struct rte_mbuf *mbuf_dst)
 {
 	/* cipher */
-	uint8_t *src = NULL, *dst = NULL, *iv, *tag, *aad;
+	uint8_t *dst = NULL, *iv, *tag, *aad;
 	int srclen, ivlen, aadlen, status = -1;
 
+	/*
+	 * Segmented destination buffer is not supported for
+	 * encryption/decryption
+	 */
+	if (!rte_pktmbuf_is_contiguous(mbuf_dst)) {
+		op->status = RTE_CRYPTO_OP_STATUS_ERROR;
+		return;
+	}
+
 	iv = op->sym->cipher.iv.data;
 	ivlen = op->sym->cipher.iv.length;
 	aad = op->sym->auth.aad.data;
@@ -741,22 +918,22 @@
 		srclen = 0;
 	else {
 		srclen = op->sym->cipher.data.length;
-		src = rte_pktmbuf_mtod_offset(mbuf_src, uint8_t *,
-				op->sym->cipher.data.offset);
 		dst = rte_pktmbuf_mtod_offset(mbuf_dst, uint8_t *,
 				op->sym->cipher.data.offset);
 	}
 
 	if (sess->cipher.direction == RTE_CRYPTO_CIPHER_OP_ENCRYPT)
 		status = process_openssl_auth_encryption_gcm(
-				src, srclen, aad, aadlen, iv, ivlen,
-				sess->cipher.key.data, dst, tag,
-				sess->cipher.ctx, sess->cipher.evp_algo);
+				mbuf_src, op->sym->cipher.data.offset, srclen,
+				aad, aadlen, iv, ivlen, sess->cipher.key.data,
+				dst, tag, sess->cipher.ctx,
+				sess->cipher.evp_algo);
 	else
 		status = process_openssl_auth_decryption_gcm(
-				src, srclen, aad, aadlen, iv, ivlen,
-				sess->cipher.key.data, dst, tag,
-				sess->cipher.ctx, sess->cipher.evp_algo);
+				mbuf_src, op->sym->cipher.data.offset, srclen,
+				aad, aadlen, iv, ivlen, sess->cipher.key.data,
+				dst, tag, sess->cipher.ctx,
+				sess->cipher.evp_algo);
 
 	if (status != 0) {
 		if (status == (-EFAULT) &&
@@ -774,12 +951,19 @@
 		(struct rte_crypto_op *op, struct openssl_session *sess,
 		struct rte_mbuf *mbuf_src, struct rte_mbuf *mbuf_dst)
 {
-	uint8_t *src, *dst, *iv;
+	uint8_t *dst, *iv;
 	int srclen, status;
 
+	/*
+	 * Segmented destination buffer is not supported for
+	 * encryption/decryption
+	 */
+	if (!rte_pktmbuf_is_contiguous(mbuf_dst)) {
+		op->status = RTE_CRYPTO_OP_STATUS_ERROR;
+		return;
+	}
+
 	srclen = op->sym->cipher.data.length;
-	src = rte_pktmbuf_mtod_offset(mbuf_src, uint8_t *,
-			op->sym->cipher.data.offset);
 	dst = rte_pktmbuf_mtod_offset(mbuf_dst, uint8_t *,
 			op->sym->cipher.data.offset);
 
@@ -787,17 +971,20 @@
 
 	if (sess->cipher.mode == OPENSSL_CIPHER_LIB)
 		if (sess->cipher.direction == RTE_CRYPTO_CIPHER_OP_ENCRYPT)
-			status = process_openssl_cipher_encrypt(src, dst, iv,
+			status = process_openssl_cipher_encrypt(mbuf_src, dst,
+					op->sym->cipher.data.offset, iv,
 					sess->cipher.key.data, srclen,
 					sess->cipher.ctx,
 					sess->cipher.evp_algo);
 		else
-			status = process_openssl_cipher_decrypt(src, dst, iv,
+			status = process_openssl_cipher_decrypt(mbuf_src, dst,
+					op->sym->cipher.data.offset, iv,
 					sess->cipher.key.data, srclen,
 					sess->cipher.ctx,
 					sess->cipher.evp_algo);
 	else
-		status = process_openssl_cipher_des3ctr(src, dst, iv,
+		status = process_openssl_cipher_des3ctr(mbuf_src, dst,
+				op->sym->cipher.data.offset, iv,
 				sess->cipher.key.data, srclen,
 				sess->cipher.ctx);
 
@@ -811,12 +998,10 @@
 		(struct rte_crypto_op *op, struct openssl_session *sess,
 		struct rte_mbuf *mbuf_src, struct rte_mbuf *mbuf_dst)
 {
-	uint8_t *src, *dst;
+	uint8_t *dst;
 	int srclen, status;
 
 	srclen = op->sym->auth.data.length;
-	src = rte_pktmbuf_mtod_offset(mbuf_src, uint8_t *,
-			op->sym->auth.data.offset);
 
 	if (sess->auth.operation == RTE_CRYPTO_AUTH_OP_VERIFY)
 		dst = (uint8_t *)rte_pktmbuf_append(mbuf_src,
@@ -831,13 +1016,14 @@
 
 	switch (sess->auth.mode) {
 	case OPENSSL_AUTH_AS_AUTH:
-		status = process_openssl_auth(src, dst,
-				NULL, NULL,	srclen,
+		status = process_openssl_auth(mbuf_src, dst,
+				op->sym->auth.data.offset, NULL, NULL, srclen,
 				sess->auth.auth.ctx, sess->auth.auth.evp_algo);
 		break;
 	case OPENSSL_AUTH_AS_HMAC:
-		status = process_openssl_auth_hmac(src, dst,
-				NULL, sess->auth.hmac.pkey, srclen,
+		status = process_openssl_auth_hmac(mbuf_src, dst,
+				op->sym->auth.data.offset, NULL,
+				sess->auth.hmac.pkey, srclen,
 				sess->auth.hmac.ctx, sess->auth.hmac.evp_algo);
 		break;
 	default:
@@ -851,8 +1037,7 @@
 			op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
 		}
 		/* Trim area used for digest from mbuf. */
-		rte_pktmbuf_trim(mbuf_src,
-				op->sym->auth.digest.length);
+		rte_pktmbuf_trim(mbuf_src, op->sym->auth.digest.length);
 	}
 
 	if (status != 0)
@@ -903,7 +1088,6 @@
 		op->sym->session = NULL;
 	}
 
-
 	if (op->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED)
 		op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
 
@@ -997,7 +1181,8 @@
 
 	dev->feature_flags = RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO |
 			RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING |
-			RTE_CRYPTODEV_FF_CPU_AESNI;
+			RTE_CRYPTODEV_FF_CPU_AESNI |
+			RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER;
 
 	/* Set vector instructions mode supported */
 	internals = dev->data->dev_private;
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4 0/3] Chained Mbufs support in SW PMDs
From: Tomasz Kulasek @ 2017-01-05 16:46 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch
In-Reply-To: <1483607556-21460-1-git-send-email-tomaszx.kulasek@intel.com>

This patch set adds support of scattered-gather list for SW PMDs.

As of now, application needs to reserve continuous block of memory for
mbufs which is not always the case. Hence needed to support chaining of
mbufs which are smaller in size but can be used if chained.


Above work involves:
--------------------

 a) Create mbuf functions to coalesce mbuf chains into a single mbuf.
 b) For each software poll mode driver code to detect chained mbufs
    support and coalesce these before preforming crypto.
 c) Add relevant unit tests to test the functionality.


Known limitations for openssl PMD:
----------------------------------

While libcrypto library expects continuous destination buffer for
output of cipher operations, implementation of openssl PMD is limited
the same way, and requires contiguous destination mbuf.


Dependencies:
-------------

While "rte_mbuf: add rte_pktmbuf_linearize" were separated from this
patch set, patch "rte_mbuf: add rte_pktmbuf_linearize" should be
applied before this one.

This patch set shares some unit tests with SGL implementation for QAT
(already merged in dpdk-next-crypto) and should be applied on top of it,
and after applying fix "app/test: fix aad padding size in SGL operation"
by Arek Kusztal.


changes in v4:
 - separated "rte_pktmbuf_linearize" implementation from this patch set
   and sent as new patch for better reviewing,

changes in v3:
 - rebased to dpdk-next-crypto
 - reused tests for AES GCM SGL support in opensll from "app/test: add
   SGL tests to cryptodev QAT suite"

changes in v2:
 - add support for sgl in openssl PMD
 - rte_pktmbuf_coalesce replaced with rte_pktmbuf_linearize
 - extended test vector data for aes gcm from 60 to 2048 bytes

Tomasz Kulasek (3):
  crypto: add sgl support in sw PMDs
  crypto: add sgl support in openssl PMD
  test: add sgl unit tests for crypto devices

 app/test/test_cryptodev.c                  |  386 ++++++++++++++++++-
 app/test/test_cryptodev.h                  |  139 +++++++
 app/test/test_cryptodev_aes_test_vectors.h |   52 +++
 app/test/test_cryptodev_blockcipher.c      |  180 +++++----
 app/test/test_cryptodev_blockcipher.h      |    1 +
 app/test/test_cryptodev_gcm_test_vectors.h |  553 ++++++++++++++++++++++++++++
 doc/guides/cryptodevs/openssl.rst          |    3 +-
 drivers/crypto/aesni_gcm/aesni_gcm_pmd.c   |   14 +
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c |   19 +-
 drivers/crypto/kasumi/rte_kasumi_pmd.c     |   13 +
 drivers/crypto/null/null_crypto_pmd.c      |    3 +-
 drivers/crypto/openssl/rte_openssl_pmd.c   |  329 +++++++++++++----
 drivers/crypto/snow3g/rte_snow3g_pmd.c     |   15 +
 drivers/crypto/zuc/rte_zuc_pmd.c           |   13 +
 lib/librte_cryptodev/rte_cryptodev.c       |    4 +-
 lib/librte_cryptodev/rte_cryptodev.h       |    2 +
 16 files changed, 1577 insertions(+), 149 deletions(-)

-- 
1.7.9.5

^ permalink raw reply

* [PATCH v4 1/3] crypto: add sgl support in sw PMDs
From: Tomasz Kulasek @ 2017-01-05 16:46 UTC (permalink / raw)
  To: dev; +Cc: pablo.de.lara.guarch
In-Reply-To: <1483634768-35012-1-git-send-email-tomaszx.kulasek@intel.com>

This patch introduces RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER feature flag
informing that selected crypto device supports segmented mbufs natively
and doesn't need to be coalesced before crypto operation.

While using segmented buffers in crypto devices may have unpredictable
results, for PMDs which doesn't support it natively, additional check is
made for debug compilation.

Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 drivers/crypto/aesni_gcm/aesni_gcm_pmd.c   |   14 ++++++++++++++
 drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c |   19 ++++++++++++++++---
 drivers/crypto/kasumi/rte_kasumi_pmd.c     |   13 +++++++++++++
 drivers/crypto/null/null_crypto_pmd.c      |    3 ++-
 drivers/crypto/snow3g/rte_snow3g_pmd.c     |   15 +++++++++++++++
 drivers/crypto/zuc/rte_zuc_pmd.c           |   13 +++++++++++++
 lib/librte_cryptodev/rte_cryptodev.c       |    4 ++--
 lib/librte_cryptodev/rte_cryptodev.h       |    2 ++
 8 files changed, 77 insertions(+), 6 deletions(-)

diff --git a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
index dba5e15..1a6120c 100644
--- a/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
+++ b/drivers/crypto/aesni_gcm/aesni_gcm_pmd.c
@@ -375,6 +375,20 @@
 			break;
 		}
 
+#ifdef RTE_LIBRTE_PMD_AESNI_GCM_DEBUG
+		if (!rte_pktmbuf_is_contiguous(ops[i]->sym->m_src) ||
+				(ops[i]->sym->m_dst != NULL &&
+				!rte_pktmbuf_is_contiguous(
+						ops[i]->sym->m_dst))) {
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			GCM_LOG_ERR("PMD supports only contiguous mbufs, "
+				"op (%p) provides noncontiguous mbuf as "
+				"source/destination buffer.\n", ops[i]);
+			qp->qp_stats.enqueue_err_count++;
+			break;
+		}
+#endif
+
 		retval = process_gcm_crypto_op(qp, ops[i]->sym, sess);
 		if (retval < 0) {
 			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
index 6d27d75..25f681b 100644
--- a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
@@ -571,15 +571,28 @@
 	int i, processed_jobs = 0;
 
 	for (i = 0; i < nb_ops; i++) {
-#ifdef RTE_LIBRTE_AESNI_MB_DEBUG
-		if (unlikely(op->type != RTE_CRYPTO_OP_TYPE_SYMMETRIC)) {
+#ifdef RTE_LIBRTE_PMD_AESNI_MB_DEBUG
+		if (unlikely(ops[i]->type != RTE_CRYPTO_OP_TYPE_SYMMETRIC)) {
 			MB_LOG_ERR("PMD only supports symmetric crypto "
 				"operation requests, op (%p) is not a "
-				"symmetric operation.", op);
+				"symmetric operation.", ops[i]);
+			qp->stats.enqueue_err_count++;
+			goto flush_jobs;
+		}
+
+		if (!rte_pktmbuf_is_contiguous(ops[i]->sym->m_src) ||
+				(ops[i]->sym->m_dst != NULL &&
+				!rte_pktmbuf_is_contiguous(
+						ops[i]->sym->m_dst))) {
+			MB_LOG_ERR("PMD supports only contiguous mbufs, "
+				"op (%p) provides noncontiguous mbuf as "
+				"source/destination buffer.\n", ops[i]);
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
 			qp->stats.enqueue_err_count++;
 			goto flush_jobs;
 		}
 #endif
+
 		sess = get_session(qp, ops[i]);
 		if (unlikely(sess == NULL)) {
 			qp->stats.enqueue_err_count++;
diff --git a/drivers/crypto/kasumi/rte_kasumi_pmd.c b/drivers/crypto/kasumi/rte_kasumi_pmd.c
index b119da2..4bdd7bb 100644
--- a/drivers/crypto/kasumi/rte_kasumi_pmd.c
+++ b/drivers/crypto/kasumi/rte_kasumi_pmd.c
@@ -455,6 +455,19 @@
 	for (i = 0; i < nb_ops; i++) {
 		curr_c_op = ops[i];
 
+#ifdef RTE_LIBRTE_PMD_KASUMI_DEBUG
+		if (!rte_pktmbuf_is_contiguous(curr_c_op->sym->m_src) ||
+				(curr_c_op->sym->m_dst != NULL &&
+				!rte_pktmbuf_is_contiguous(
+						curr_c_op->sym->m_dst))) {
+			KASUMI_LOG_ERR("PMD supports only contiguous mbufs, "
+				"op (%p) provides noncontiguous mbuf as "
+				"source/destination buffer.\n", curr_c_op);
+			curr_c_op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			break;
+		}
+#endif
+
 		/* Set status as enqueued (not processed yet) by default. */
 		curr_c_op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
 
diff --git a/drivers/crypto/null/null_crypto_pmd.c b/drivers/crypto/null/null_crypto_pmd.c
index c69606b..c37d3d6 100644
--- a/drivers/crypto/null/null_crypto_pmd.c
+++ b/drivers/crypto/null/null_crypto_pmd.c
@@ -216,7 +216,8 @@
 	dev->enqueue_burst = null_crypto_pmd_enqueue_burst;
 
 	dev->feature_flags = RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO |
-			RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING;
+			RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING |
+			RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER;
 
 	internals = dev->data->dev_private;
 
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
index 3b4292a..9a6f16d 100644
--- a/drivers/crypto/snow3g/rte_snow3g_pmd.c
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -330,6 +330,21 @@
 	unsigned i;
 	unsigned enqueued_ops, processed_ops;
 
+#ifdef RTE_LIBRTE_PMD_SNOW3G_DEBUG
+	for (i = 0; i < num_ops; i++) {
+		if (!rte_pktmbuf_is_contiguous(ops[i]->sym->m_src) ||
+				(ops[i]->sym->m_dst != NULL &&
+				!rte_pktmbuf_is_contiguous(
+						ops[i]->sym->m_dst))) {
+			SNOW3G_LOG_ERR("PMD supports only contiguous mbufs, "
+				"op (%p) provides noncontiguous mbuf as "
+				"source/destination buffer.\n", ops[i]);
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			return 0;
+		}
+	}
+#endif
+
 	switch (session->op) {
 	case SNOW3G_OP_ONLY_CIPHER:
 		processed_ops = process_snow3g_cipher_op(ops,
diff --git a/drivers/crypto/zuc/rte_zuc_pmd.c b/drivers/crypto/zuc/rte_zuc_pmd.c
index 3849119..bf53f76 100644
--- a/drivers/crypto/zuc/rte_zuc_pmd.c
+++ b/drivers/crypto/zuc/rte_zuc_pmd.c
@@ -211,6 +211,19 @@
 			break;
 		}
 
+#ifdef RTE_LIBRTE_PMD_ZUC_DEBUG
+		if (!rte_pktmbuf_is_contiguous(ops[i]->sym->m_src) ||
+				(ops[i]->sym->m_dst != NULL &&
+				!rte_pktmbuf_is_contiguous(
+						ops[i]->sym->m_dst))) {
+			ZUC_LOG_ERR("PMD supports only contiguous mbufs, "
+				"op (%p) provides noncontiguous mbuf as "
+				"source/destination buffer.\n", ops[i]);
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			break;
+		}
+#endif
+
 		src[i] = rte_pktmbuf_mtod(ops[i]->sym->m_src, uint8_t *) +
 				(ops[i]->sym->cipher.data.offset >> 3);
 		dst[i] = ops[i]->sym->m_dst ?
diff --git a/lib/librte_cryptodev/rte_cryptodev.c b/lib/librte_cryptodev/rte_cryptodev.c
index 54e95d5..bbab4b3 100644
--- a/lib/librte_cryptodev/rte_cryptodev.c
+++ b/lib/librte_cryptodev/rte_cryptodev.c
@@ -211,13 +211,13 @@ struct rte_cryptodev_callback {
 		return "CPU_AESNI";
 	case RTE_CRYPTODEV_FF_HW_ACCELERATED:
 		return "HW_ACCELERATED";
-
+	case RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER:
+		return "MBUF_SCATTER_GATHER";
 	default:
 		return NULL;
 	}
 }
 
-
 int
 rte_cryptodev_create_vdev(const char *name, const char *args)
 {
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 29d8eec..fa311a9 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -227,6 +227,8 @@ struct rte_cryptodev_capabilities {
 /**< Operations are off-loaded to an external hardware accelerator */
 #define	RTE_CRYPTODEV_FF_CPU_AVX512		(1ULL << 8)
 /**< Utilises CPU SIMD AVX512 instructions */
+#define	RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER	(1ULL << 9)
+/**< Scatter-gather mbufs are supported */
 
 
 /**
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v4] rte_mbuf: add rte_pktmbuf_linearize
From: Tomasz Kulasek @ 2017-01-05 16:44 UTC (permalink / raw)
  To: dev; +Cc: Pablo de Lara, Olivier Matz
In-Reply-To: <1483607556-21460-1-git-send-email-tomaszx.kulasek@intel.com>

This patch adds function rte_pktmbuf_linearize to let crypto PMD coalesce
chained mbuf before crypto operation and extend their capabilities to
support segmented mbufs when device cannot handle them natively.

Included unit tests for rte_pktmbuf_linearize functionality:

 1) Creates banch of segmented mbufs with different size and number of
    segments.
 2) Generates pkt_len bytes of random data.
 3) Fills noncontigouos mbuf with randomly generated data.
 4) Uses rte_pktmbuf_linearize to coalesce segmented buffer into one
    contiguous.
 5) Verifies data in linearized buffer.

Dependencies:

This patch is rebased to the dpdk-next-crypto and should be applied
before "Chained Mbufs support in SW PMDs" patchset.


changes in v4:
 - separated from "Chained Mbufs support in SW PMDs" patch set for
   better reviewing,
 - merged "rte_pktmbuf_linearize" implementation with unit tests,

changes in v3:
 - rebased to dpdk-next-crypto

changes in v2:
 - rte_pktmbuf_coalesce replaced with rte_pktmbuf_linearize


Cc: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Cc: Olivier Matz <olivier.matz@6wind.com>
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
---
 app/test/test_mbuf.c       |  123 ++++++++++++++++++++++++++++++++++++++++++++
 lib/librte_mbuf/rte_mbuf.h |   56 ++++++++++++++++++++
 2 files changed, 179 insertions(+)

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index c0823ea..39577e7 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -930,6 +930,124 @@
 	return 0;
 }
 
+static int
+test_mbuf_linearize(int pkt_len, int nb_segs) {
+
+	struct rte_mbuf *m = NULL, *mbuf_src = NULL;
+	uint8_t data[pkt_len], *src, *dst;
+	int data_len = 0;
+	int i, size;
+	int t_len;
+
+	if (pkt_len < 1) {
+		printf("Packet size must be 1 or more (is %d)\n", pkt_len);
+		return -1;
+	}
+
+	if (nb_segs < 1) {
+		printf("Number of segments must be 1 or more (is %d)\n",
+				nb_segs);
+		return -1;
+	}
+
+	/* Setup buffer */
+	for (i = 0; i < pkt_len; i++)
+		data[i] = (uint8_t) rte_rand();
+
+	t_len = pkt_len >= nb_segs ? pkt_len / nb_segs : 1;
+	src = data;
+	size = pkt_len;
+
+	/* Create chained mbuf_src and fill it generated data */
+	for (i = 0; size > 0; i++) {
+
+		m = rte_pktmbuf_alloc(pktmbuf_pool);
+		if (i == 0)
+			mbuf_src = m;
+
+		if (!m) {
+			printf("Cannot create segment for source mbuf");
+			goto fail;
+		}
+
+		/* Make sure if tailroom is zeroed */
+		memset(rte_pktmbuf_mtod(m, uint8_t *), 0,
+				rte_pktmbuf_tailroom(m));
+
+		data_len = size > t_len ? t_len : size;
+		dst = (uint8_t *)rte_pktmbuf_append(m, data_len);
+		if (!dst) {
+			printf("Cannot append %d bytes to the mbuf\n",
+					data_len);
+			goto fail;
+		}
+
+		rte_memcpy(dst, src, data_len);
+		src += data_len;
+
+		if (mbuf_src != m)
+			rte_pktmbuf_chain(mbuf_src, m);
+
+		size -= data_len;
+
+	}
+
+	/* Create destination buffer to store coalesced data */
+	if (rte_pktmbuf_linearize(mbuf_src)) {
+		printf("Mbuf linearization failed\n");
+		goto fail;
+	}
+
+	if (!rte_pktmbuf_is_contiguous(mbuf_src)) {
+		printf("Source buffer should be contiguous after "
+				"linearization\n");
+		goto fail;
+	}
+
+	src = rte_pktmbuf_mtod(mbuf_src, uint8_t *);
+
+	if (memcmp(src, data, rte_pktmbuf_pkt_len(mbuf_src))) {
+		printf("Incorrect data in coalesced mbuf\n");
+		goto fail;
+	}
+
+	if (mbuf_src)
+		rte_pktmbuf_free(mbuf_src);
+	return 0;
+
+fail:
+	if (mbuf_src)
+		rte_pktmbuf_free(mbuf_src);
+	return -1;
+}
+
+static int
+test_mbuf_linearize_check(void)
+{
+	struct test_mbuf_array {
+		int size;
+		int nb_segs;
+	} mbuf_array[5] = {
+			{ 128, 1 },
+			{ 64, 64 },
+			{ 512, 10 },
+			{ 250, 11 },
+			{ 123, 8 },
+	};
+	unsigned int i;
+
+	printf("Test mbuf linearize API\n");
+
+	for (i = 0; i < RTE_DIM(mbuf_array); i++)
+		if (test_mbuf_linearize(mbuf_array[i].size,
+				mbuf_array[i].nb_segs)) {
+			printf("Test failed for %d, %d\n", mbuf_array[i].size,
+					mbuf_array[i].nb_segs);
+			return -1;
+		}
+
+	return 0;
+}
 
 static int
 test_mbuf(void)
@@ -1023,6 +1141,11 @@
 		printf("test_failing_mbuf_sanity_check() failed\n");
 		return -1;
 	}
+
+	if (test_mbuf_linearize_check() < 0) {
+		printf("test_mbuf_linearize_check() failed\n");
+		return -1;
+	}
 	return 0;
 }
 
diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h
index ead7c6e..b11a31d 100644
--- a/lib/librte_mbuf/rte_mbuf.h
+++ b/lib/librte_mbuf/rte_mbuf.h
@@ -1647,6 +1647,62 @@ static inline int rte_pktmbuf_chain(struct rte_mbuf *head, struct rte_mbuf *tail
 }
 
 /**
+ * Linearize data in mbuf.
+ *
+ * This function coalesce mbuf merging data in the first segment, unchaining
+ * rest, and then frees them.
+ *
+ * All operations are done in-place, so the structure of incoming mbuf
+ * is changed.
+ *
+ * @param mbuf
+ *   mbuf to linearize
+ * @return
+ *   - 0, on success
+ *   - -1, on error
+ */
+static inline int
+rte_pktmbuf_linearize(struct rte_mbuf *mbuf)
+{
+	int l, n;
+	struct rte_mbuf *m;
+	struct rte_mbuf *m_next;
+	char *buffer;
+
+	if (rte_pktmbuf_is_contiguous(mbuf))
+		return 0;
+
+	/* Extend first segment to the total packet length
+	 */
+	n = rte_pktmbuf_pkt_len(mbuf) - rte_pktmbuf_data_len(mbuf);
+
+	if (unlikely(n > rte_pktmbuf_tailroom(mbuf)))
+		return -1;
+
+	buffer = rte_pktmbuf_mtod_offset(mbuf, char *, mbuf->data_len);
+	mbuf->data_len = (uint16_t)(mbuf->pkt_len);
+
+	/* Append data from next segments to the first one
+	 */
+	m = mbuf->next;
+	while (m != NULL) {
+		m_next = m->next;
+
+		l = rte_pktmbuf_data_len(m);
+		rte_memcpy(buffer, rte_pktmbuf_mtod(m, char *), l);
+		buffer += l;
+
+		rte_pktmbuf_free_seg(m);
+		m = m_next;
+	}
+
+	mbuf->next = NULL;
+	mbuf->nb_segs = 1;
+
+	return 0;
+}
+
+/**
  * Dump an mbuf structure to a file.
  *
  * Dump all fields for the given packet mbuf and all its associated
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH] net/mlx5: fix Tx doorbell
From: Adrien Mazarguil @ 2017-01-05 16:32 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: Nelio Laranjeiro, dev, stable
In-Reply-To: <2da35386-f774-a1ca-c4f2-cc77f74f6e2c@intel.com>

Hi Ferruh,

On Thu, Jan 05, 2017 at 03:19:35PM +0000, Ferruh Yigit wrote:
> On 12/9/2016 1:27 PM, Nelio Laranjeiro wrote:
> > Too much data is uselessly written to the Tx doorbell.
> > 
> > Fixes: 1d88ba171942 ("net/mlx5: refactor Tx data path")
> > 
> > Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
> > Acked-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
> > 
> 
> Applied to dpdk-next-net/master, thanks.
> 
> Is not CC'ing stable intentional, since this patch depends on a patch
> introduced in this release? If not intentional, please CC stable.

I intended to update the commit message for this patch as in the meantime we
discovered it addresses a significant regression introduced in v16.11.

CC'ing stable now.

If possible, can you amend the commit log with:

---

net/mlx5: fix Tx doorbell

Too much data is uselessly written to the Tx doorbell, which since v16.11
may also cause Tx queues to behave erratically and crash applications.

This regression was seen on VF devices when the BlueFlame buffer size is
zero (txq->cqe_n == 0) due to the following change:

 -       cqe = &(*txq->cqes)[ci & (txq->cqe_n - 1)].cqe64;
 +       cqe = &(*txq->cqes)[ci & ((1 << txq->cqe_n) - 1)];

Fixes: 1d88ba171942 ("net/mlx5: refactor Tx data path")
Fixes: e2f116ee3cac ("net/mlx5: reduce memory overhead for CQE handling")

Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
Acked-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Cc: stable@dpdk.org

---

Thanks,

-- 
Adrien Mazarguil
6WIND

^ permalink raw reply

* Re: [PATCH v2 1/5] eal: Set numa node value for system which not support NUMA.
From: Stephen Hemminger @ 2017-01-05 16:26 UTC (permalink / raw)
  To: nickcooper-zhangtonghao; +Cc: dev
In-Reply-To: <1483617709-7088-1-git-send-email-nic@opencloud.tech>

On Thu,  5 Jan 2017 04:01:45 -0800
nickcooper-zhangtonghao <nic@opencloud.tech> wrote:

> +		/* The NUMA node information for PCI devices provided through
> +		 * sysfs is invalid for AMD Opteron(TM) Processor 62xx and 63xx
> +		 * on Red Hat Enterprise Linux 6, and VMs on some hypervisors.
> +		 * In the upstream linux kernel, the numa_node is an integer,
> +		 * which data type is int, not unsigned long.
> +		 */
> +		dev->device.numa_node = (int)tmp > 0 ? (int)tmp : 0;
>  	}

It is good to see more checking for valid values.  I suspect that other systems
may have the same problem.  My preference would to have the code comment generic
and to have the precise details of about where this was observed in the commit
log. 

The following would do same thing but be simpler:

diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index 43501342..9f09cd98 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -306,19 +306,12 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus,
 			dev->max_vfs = (uint16_t)tmp;
 	}
 
-	/* get numa node */
+	/* get numa node, default to 0 if not present */
 	snprintf(filename, sizeof(filename), "%s/numa_node",
 		 dirname);
-	if (access(filename, R_OK) != 0) {
-		/* if no NUMA support, set default to 0 */
-		dev->device.numa_node = 0;
-	} else {
-		if (eal_parse_sysfs_value(filename, &tmp) < 0) {
-			free(dev);
-			return -1;
-		}
+	if (eal_parse_sysfs_value(filename, &tmp) == 0 &&
+	    tmp < RTE_MAX_NUMA_NODES)
 		dev->device.numa_node = tmp;
-	}
 
 	/* parse resources */
 	snprintf(filename, sizeof(filename), "%s/resource", dirname);

^ permalink raw reply related

* Re: [PATCH] net/mlx5: fix Tx doorbell
From: Nélio Laranjeiro @ 2017-01-05 16:25 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev
In-Reply-To: <2da35386-f774-a1ca-c4f2-cc77f74f6e2c@intel.com>

On Thu, Jan 05, 2017 at 03:19:35PM +0000, Ferruh Yigit wrote:
> On 12/9/2016 1:27 PM, Nelio Laranjeiro wrote:
> > Too much data is uselessly written to the Tx doorbell.
> > 
> > Fixes: 1d88ba171942 ("net/mlx5: refactor Tx data path")
> > 
> > Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
> > Acked-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
> > 
> 
> Applied to dpdk-next-net/master, thanks.
> 
> Is not CC'ing stable intentional, since this patch depends on a patch
> introduced in this release? If not intentional, please CC stable.

Hi Ferruh,

It was intentional, this commit won't apply as is on stable branch.

Thanks for the remind,

-- 
Nélio Laranjeiro
6WIND

^ permalink raw reply

* Re: [PATCH v2 1/5] eal: Set numa node value for system which not support NUMA.
From: Stephen Hemminger @ 2017-01-05 16:17 UTC (permalink / raw)
  To: nickcooper-zhangtonghao; +Cc: dev
In-Reply-To: <1483617709-7088-1-git-send-email-nic@opencloud.tech>

On Thu,  5 Jan 2017 04:01:45 -0800
nickcooper-zhangtonghao <nic@opencloud.tech> wrote:

> The NUMA node information for PCI devices provided through
> sysfs is invalid for AMD Opteron(TM) Processor 62xx and 63xx
> on Red Hat Enterprise Linux 6, and VMs on some hypervisors.
> 
> Signed-off-by: nickcooper-zhangtonghao <nic@opencloud.tech>

That name seems a bit unusual. Is that your legal name or a partnership?

The Signed-off-by line has legal significance and it is important that
you use your legal name. Please use the name you would use when
signing a legal document (like buying a house or renting).

^ permalink raw reply

* Re: Running DPDK as an unprivileged user
From: Tan, Jianfeng @ 2017-01-05 15:52 UTC (permalink / raw)
  To: Walker, Benjamin, dev@dpdk.org
In-Reply-To: <1483565664.9482.3.camel@intel.com>

Hi Benjamin,


On 1/5/2017 5:34 AM, Walker, Benjamin wrote:
> On Wed, 2017-01-04 at 19:39 +0800, Tan, Jianfeng wrote:
>> Hi Benjamin,
>>
>>
>> On 12/30/2016 4:41 AM, Walker, Benjamin wrote:
>>> DPDK today begins by allocating all of the required
>>> hugepages, then finds all of the physical addresses for
>>> those hugepages using /proc/self/pagemap, sorts the
>>> hugepages by physical address, then remaps the pages to
>>> contiguous virtual addresses. Later on and if vfio is
>>> enabled, it asks vfio to pin the hugepages and to set their
>>> DMA addresses in the IOMMU to be the physical addresses
>>> discovered earlier. Of course, running as an unprivileged
>>> user means all of the physical addresses in
>>> /proc/self/pagemap are just 0, so this doesn't end up
>>> working. Further, there is no real reason to choose the
>>> physical address as the DMA address in the IOMMU - it would
>>> be better to just count up starting at 0.
>> Why not just using virtual address as the DMA address in this case to
>> avoid maintaining another kind of addresses?
> That's a valid choice, although I'm just storing the DMA address in the
> physical address field that already exists. You either have a physical
> address or a DMA address and never both.

Yes, I understand that's why you cast the second question below.

>
>>>    Also, because the
>>> pages are pinned after the virtual to physical mapping is
>>> looked up, there is a window where a page could be moved.
>>> Hugepage mappings can be moved on more recent kernels (at
>>> least 4.x), and the reliability of hugepages having static
>>> mappings decreases with every kernel release.
>> Do you mean kernel might take back a physical page after mapping it to a
>> virtual page (maybe copy the data to another physical page)? Could you
>> please show some links or kernel commits?
> Yes - the kernel can move a physical page to another physical page
> and change the virtual mapping at any time. For a concise example
> see 'man migrate_pages(2)', or for a more serious example the code
> that performs memory page compaction in the kernel which was
> recently extended to support hugepages.
>
> Before we go down the path of me proving that the mapping isn't static,
> let me turn that line of thinking around. Do you have any documentation
> demonstrating that the mapping is static? It's not static for 4k pages, so
> why are we assuming that it is static for 2MB pages? I understand that
> it happened to be static for some versions of the kernel, but my understanding
> is that this was purely by coincidence and never by intention.

Thank you for the information. Based on what you provide above, I 
realize this behavior could happen since long time ago.

>
>>> Note that this
>>> probably means that using uio on recent kernels is subtly
>>> broken and cannot be supported going forward because there
>>> is no uio mechanism to pin the memory.
>>>
>>> The first open question I have is whether DPDK should allow
>>> uio at all on recent (4.x) kernels. My current understanding
>>> is that there is no way to pin memory and hugepages can now
>>> be moved around, so uio would be unsafe. What does the
>>> community think here?

Back to this question, removing uio support in DPDK seems a little 
overkill to me. Can we just document it down? Like, firstly warn users 
do not invoke migrate_pages() or move_pages() to a DPDK process; as for 
the kcompactd daemon and some more cases (like compaction could be 
triggered by alloc_pages()), could we just recommend to disable 
CONFIG_COMPACTION?

Another side, how does vfio pin those memory? Through memlock (from code 
in vfio_pin_pages())? So why not just mlock those hugepages?

>>>
>>> My second question is whether the user should be allowed to
>>> mix uio and vfio usage simultaneously. For vfio, the
>>> physical addresses are really DMA addresses and are best
>>> when arbitrarily chosen to appear sequential relative to
>>> their virtual addresses.
>> Why "sequential relative to their virtual addresses"? IOMMU table is for
>> DMA addr -> physical addr mapping. So we need to DMA addresses
>> "sequential relative to their physical addresses"? Based on your above
>> analysis on how hugepages are initialized, virtual addresses is a good
>> candidate for DMA address?
> The code already goes through a separate organizational step on all of
> the pages that remaps the virtual addresses such that they're sequential
> relative to the physical backing pages, so this mostly ends up as the same
> thing.

Agreed.

> Choosing to use the virtual address is a totally valid choice, but I worry it
> may lead to confusion during debugging or in a multi-process scenario.

Make sense.

Thanks,
Jianfeng

^ permalink raw reply

* [PATCH v6 17/17] net/i40e: flush tunnel filters
From: Beilei Xing @ 2017-01-05 15:46 UTC (permalink / raw)
  To: jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-1-git-send-email-beilei.xing@intel.com>

This patch adds i40e_flow_flush_tunnel_filter
function to flush all tunnel filters, including
filters in SW and HW.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
---
 drivers/net/i40e/i40e_flow.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index 1909455..e080a00 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -124,6 +124,7 @@ static int i40e_flow_destroy_tunnel_filter(struct i40e_pf *pf,
 					   struct i40e_tunnel_filter *filter);
 static int i40e_flow_flush_fdir_filter(struct i40e_pf *pf);
 static int i40e_flow_flush_ethertype_filter(struct i40e_pf *pf);
+static int i40e_flow_flush_tunnel_filter(struct i40e_pf *pf);
 
 const struct rte_flow_ops i40e_flow_ops = {
 	.validate = i40e_flow_validate,
@@ -1749,6 +1750,14 @@ i40e_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
 		return -rte_errno;
 	}
 
+	ret = i40e_flow_flush_tunnel_filter(pf);
+	if (ret) {
+		rte_flow_error_set(error, -ret,
+				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				   "Failed to flush tunnel flows.");
+		return -rte_errno;
+	}
+
 	return ret;
 }
 
@@ -1811,3 +1820,31 @@ i40e_flow_flush_ethertype_filter(struct i40e_pf *pf)
 
 	return ret;
 }
+
+/* Flush all tunnel filters */
+static int
+i40e_flow_flush_tunnel_filter(struct i40e_pf *pf)
+{
+	struct i40e_tunnel_filter_list
+		*tunnel_list = &pf->tunnel.tunnel_list;
+	struct i40e_tunnel_filter *filter;
+	struct i40e_flow *flow;
+	void *temp;
+	int ret = 0;
+
+	while ((filter = TAILQ_FIRST(tunnel_list))) {
+		ret = i40e_flow_destroy_tunnel_filter(pf, filter);
+		if (ret)
+			return ret;
+	}
+
+	/* Delete tunnel flows in flow list. */
+	TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) {
+		if (flow->filter_type == RTE_ETH_FILTER_TUNNEL) {
+			TAILQ_REMOVE(&pf->flow_list, flow, node);
+			rte_free(flow);
+		}
+	}
+
+	return ret;
+}
-- 
2.5.5

^ permalink raw reply related

* [PATCH v6 16/17] net/i40e: flush ethertype filters
From: Beilei Xing @ 2017-01-05 15:46 UTC (permalink / raw)
  To: jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-1-git-send-email-beilei.xing@intel.com>

This patch adds i40e_flow_flush_ethertype_filter
function to flush all ethertype filters, including
filters in SW and HW.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
---
 drivers/net/i40e/i40e_flow.c | 41 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index f37bd76..1909455 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -123,6 +123,7 @@ static int i40e_flow_destroy_ethertype_filter(struct i40e_pf *pf,
 static int i40e_flow_destroy_tunnel_filter(struct i40e_pf *pf,
 					   struct i40e_tunnel_filter *filter);
 static int i40e_flow_flush_fdir_filter(struct i40e_pf *pf);
+static int i40e_flow_flush_ethertype_filter(struct i40e_pf *pf);
 
 const struct rte_flow_ops i40e_flow_ops = {
 	.validate = i40e_flow_validate,
@@ -1733,10 +1734,20 @@ i40e_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
 	int ret;
 
 	ret = i40e_flow_flush_fdir_filter(pf);
-	if (ret)
+	if (ret) {
 		rte_flow_error_set(error, -ret,
 				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 				   "Failed to flush FDIR flows.");
+		return -rte_errno;
+	}
+
+	ret = i40e_flow_flush_ethertype_filter(pf);
+	if (ret) {
+		rte_flow_error_set(error, -ret,
+				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				   "Failed to ethertype flush flows.");
+		return -rte_errno;
+	}
 
 	return ret;
 }
@@ -1772,3 +1783,31 @@ i40e_flow_flush_fdir_filter(struct i40e_pf *pf)
 
 	return ret;
 }
+
+/* Flush all ethertype filters */
+static int
+i40e_flow_flush_ethertype_filter(struct i40e_pf *pf)
+{
+	struct i40e_ethertype_filter_list
+		*ethertype_list = &pf->ethertype.ethertype_list;
+	struct i40e_ethertype_filter *filter;
+	struct i40e_flow *flow;
+	void *temp;
+	int ret = 0;
+
+	while ((filter = TAILQ_FIRST(ethertype_list))) {
+		ret = i40e_flow_destroy_ethertype_filter(pf, filter);
+		if (ret)
+			return ret;
+	}
+
+	/* Delete ethertype flows in flow list. */
+	TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) {
+		if (flow->filter_type == RTE_ETH_FILTER_ETHERTYPE) {
+			TAILQ_REMOVE(&pf->flow_list, flow, node);
+			rte_free(flow);
+		}
+	}
+
+	return ret;
+}
-- 
2.5.5

^ permalink raw reply related

* [PATCH v6 15/17] net/i40e: add flow flush function
From: Beilei Xing @ 2017-01-05 15:46 UTC (permalink / raw)
  To: jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-1-git-send-email-beilei.xing@intel.com>

This patch adds i40e_flow_flush function to flush all
filters for users. And flow director flush function
is involved first.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
---
 drivers/net/i40e/i40e_ethdev.h |  1 +
 drivers/net/i40e/i40e_fdir.c   |  4 +---
 drivers/net/i40e/i40e_flow.c   | 51 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 0088351..198548a 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -793,6 +793,7 @@ int i40e_add_del_fdir_filter(struct rte_eth_dev *dev,
 int i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
 			       struct rte_eth_tunnel_filter_conf *tunnel_filter,
 			       uint8_t add);
+int i40e_fdir_flush(struct rte_eth_dev *dev);
 
 #define I40E_DEV_TO_PCI(eth_dev) \
 	RTE_DEV_TO_PCI((eth_dev)->device)
diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c
index 91d91aa..67d63ff 100644
--- a/drivers/net/i40e/i40e_fdir.c
+++ b/drivers/net/i40e/i40e_fdir.c
@@ -119,8 +119,6 @@ static int i40e_fdir_filter_programming(struct i40e_pf *pf,
 			enum i40e_filter_pctype pctype,
 			const struct rte_eth_fdir_filter *filter,
 			bool add);
-static int i40e_fdir_flush(struct rte_eth_dev *dev);
-
 static int i40e_fdir_filter_convert(const struct rte_eth_fdir_filter *input,
 			 struct i40e_fdir_filter *filter);
 static struct i40e_fdir_filter *
@@ -1325,7 +1323,7 @@ i40e_fdir_filter_programming(struct i40e_pf *pf,
  * i40e_fdir_flush - clear all filters of Flow Director table
  * @pf: board private structure
  */
-static int
+int
 i40e_fdir_flush(struct rte_eth_dev *dev)
 {
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index f56c404..f37bd76 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -71,6 +71,8 @@ static struct rte_flow *i40e_flow_create(struct rte_eth_dev *dev,
 static int i40e_flow_destroy(struct rte_eth_dev *dev,
 			     struct rte_flow *flow,
 			     struct rte_flow_error *error);
+static int i40e_flow_flush(struct rte_eth_dev *dev,
+			   struct rte_flow_error *error);
 static int
 i40e_flow_parse_ethertype_pattern(struct rte_eth_dev *dev,
 				  const struct rte_flow_item *pattern,
@@ -120,11 +122,13 @@ static int i40e_flow_destroy_ethertype_filter(struct i40e_pf *pf,
 				      struct i40e_ethertype_filter *filter);
 static int i40e_flow_destroy_tunnel_filter(struct i40e_pf *pf,
 					   struct i40e_tunnel_filter *filter);
+static int i40e_flow_flush_fdir_filter(struct i40e_pf *pf);
 
 const struct rte_flow_ops i40e_flow_ops = {
 	.validate = i40e_flow_validate,
 	.create = i40e_flow_create,
 	.destroy = i40e_flow_destroy,
+	.flush = i40e_flow_flush,
 };
 
 union i40e_filter_t cons_filter;
@@ -1721,3 +1725,50 @@ i40e_flow_destroy_tunnel_filter(struct i40e_pf *pf,
 
 	return ret;
 }
+
+static int
+i40e_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	int ret;
+
+	ret = i40e_flow_flush_fdir_filter(pf);
+	if (ret)
+		rte_flow_error_set(error, -ret,
+				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				   "Failed to flush FDIR flows.");
+
+	return ret;
+}
+
+static int
+i40e_flow_flush_fdir_filter(struct i40e_pf *pf)
+{
+	struct rte_eth_dev *dev = pf->adapter->eth_dev;
+	struct i40e_fdir_info *fdir_info = &pf->fdir;
+	struct i40e_fdir_filter *fdir_filter;
+	struct i40e_flow *flow;
+	void *temp;
+	int ret;
+
+	ret = i40e_fdir_flush(dev);
+	if (!ret) {
+		/* Delete FDIR filters in FDIR list. */
+		while ((fdir_filter = TAILQ_FIRST(&fdir_info->fdir_list))) {
+			ret = i40e_sw_fdir_filter_del(pf,
+						      &fdir_filter->fdir.input);
+			if (ret < 0)
+				return ret;
+		}
+
+		/* Delete FDIR flows in flow list. */
+		TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) {
+			if (flow->filter_type == RTE_ETH_FILTER_FDIR) {
+				TAILQ_REMOVE(&pf->flow_list, flow, node);
+				rte_free(flow);
+			}
+		}
+	}
+
+	return ret;
+}
-- 
2.5.5

^ permalink raw reply related

* [PATCH v6 14/17] net/i40e: destroy flow directory filter
From: Beilei Xing @ 2017-01-05 15:46 UTC (permalink / raw)
  To: jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-1-git-send-email-beilei.xing@intel.com>

This patch supports destroying a flow directory filter
for users.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
---
 drivers/net/i40e/i40e_flow.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index 2603e9e..f56c404 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -1630,6 +1630,10 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
 		ret = i40e_flow_destroy_tunnel_filter(pf,
 			      (struct i40e_tunnel_filter *)pmd_flow->rule);
 		break;
+	case RTE_ETH_FILTER_FDIR:
+		ret = i40e_add_del_fdir_filter(dev,
+		       &((struct i40e_fdir_filter *)pmd_flow->rule)->fdir, 0);
+		break;
 	default:
 		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
 			    filter_type);
-- 
2.5.5

^ permalink raw reply related

* [PATCH v6 13/17] net/i40e: destroy tunnel filter
From: Beilei Xing @ 2017-01-05 15:46 UTC (permalink / raw)
  To: jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-1-git-send-email-beilei.xing@intel.com>

This patch adds i40e_flow_destroy_tunnel_filter
function to destroy a tunnel filter for users.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
---
 drivers/net/i40e/i40e_flow.c | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index fc633cd..2603e9e 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -118,6 +118,8 @@ static int i40e_flow_parse_tunnel_filter(struct rte_eth_dev *dev,
 					 union i40e_filter_t *filter);
 static int i40e_flow_destroy_ethertype_filter(struct i40e_pf *pf,
 				      struct i40e_ethertype_filter *filter);
+static int i40e_flow_destroy_tunnel_filter(struct i40e_pf *pf,
+					   struct i40e_tunnel_filter *filter);
 
 const struct rte_flow_ops i40e_flow_ops = {
 	.validate = i40e_flow_validate,
@@ -1624,6 +1626,10 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
 		ret = i40e_flow_destroy_ethertype_filter(pf,
 			 (struct i40e_ethertype_filter *)pmd_flow->rule);
 		break;
+	case RTE_ETH_FILTER_TUNNEL:
+		ret = i40e_flow_destroy_tunnel_filter(pf,
+			      (struct i40e_tunnel_filter *)pmd_flow->rule);
+		break;
 	default:
 		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
 			    filter_type);
@@ -1676,3 +1682,38 @@ i40e_flow_destroy_ethertype_filter(struct i40e_pf *pf,
 
 	return ret;
 }
+
+static int
+i40e_flow_destroy_tunnel_filter(struct i40e_pf *pf,
+				struct i40e_tunnel_filter *filter)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	struct i40e_vsi *vsi = pf->main_vsi;
+	struct i40e_aqc_add_remove_cloud_filters_element_data cld_filter;
+	struct i40e_tunnel_rule *tunnel_rule = &pf->tunnel;
+	struct i40e_tunnel_filter *node;
+	int ret = 0;
+
+	memset(&cld_filter, 0, sizeof(cld_filter));
+	ether_addr_copy((struct ether_addr *)&filter->input.outer_mac,
+			(struct ether_addr *)&cld_filter.outer_mac);
+	ether_addr_copy((struct ether_addr *)&filter->input.inner_mac,
+			(struct ether_addr *)&cld_filter.inner_mac);
+	cld_filter.inner_vlan = filter->input.inner_vlan;
+	cld_filter.flags = filter->input.flags;
+	cld_filter.tenant_id = filter->input.tenant_id;
+	cld_filter.queue_number = filter->queue;
+
+	ret = i40e_aq_remove_cloud_filters(hw, vsi->seid,
+					   &cld_filter, 1);
+	if (ret < 0)
+		return ret;
+
+	node = i40e_sw_tunnel_filter_lookup(tunnel_rule, &filter->input);
+	if (!node)
+		return -EINVAL;
+
+	ret = i40e_sw_tunnel_filter_del(pf, &node->input);
+
+	return ret;
+}
-- 
2.5.5

^ permalink raw reply related

* [PATCH v6 12/17] net/i40e: destroy ethertype filter
From: Beilei Xing @ 2017-01-05 15:46 UTC (permalink / raw)
  To: jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-1-git-send-email-beilei.xing@intel.com>

This patch adds i40e_flow_destroy_ethertype_filter
function to destroy a ethertype filter for users.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
---
 drivers/net/i40e/i40e_flow.c | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index 4daaca0..fc633cd 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -116,6 +116,8 @@ static int i40e_flow_parse_tunnel_filter(struct rte_eth_dev *dev,
 					 const struct rte_flow_action actions[],
 					 struct rte_flow_error *error,
 					 union i40e_filter_t *filter);
+static int i40e_flow_destroy_ethertype_filter(struct i40e_pf *pf,
+				      struct i40e_ethertype_filter *filter);
 
 const struct rte_flow_ops i40e_flow_ops = {
 	.validate = i40e_flow_validate,
@@ -1618,6 +1620,10 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
 	int ret = 0;
 
 	switch (filter_type) {
+	case RTE_ETH_FILTER_ETHERTYPE:
+		ret = i40e_flow_destroy_ethertype_filter(pf,
+			 (struct i40e_ethertype_filter *)pmd_flow->rule);
+		break;
 	default:
 		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
 			    filter_type);
@@ -1635,3 +1641,38 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
 
 	return ret;
 }
+
+static int
+i40e_flow_destroy_ethertype_filter(struct i40e_pf *pf,
+				   struct i40e_ethertype_filter *filter)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
+	struct i40e_ethertype_filter *node;
+	struct i40e_control_filter_stats stats;
+	uint16_t flags = 0;
+	int ret = 0;
+
+	if (!(filter->flags & RTE_ETHTYPE_FLAGS_MAC))
+		flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC;
+	if (filter->flags & RTE_ETHTYPE_FLAGS_DROP)
+		flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP;
+	flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE;
+
+	memset(&stats, 0, sizeof(stats));
+	ret = i40e_aq_add_rem_control_packet_filter(hw,
+				    filter->input.mac_addr.addr_bytes,
+				    filter->input.ether_type,
+				    flags, pf->main_vsi->seid,
+				    filter->queue, 0, &stats, NULL);
+	if (ret < 0)
+		return ret;
+
+	node = i40e_sw_ethertype_filter_lookup(ethertype_rule, &filter->input);
+	if (!node)
+		return -EINVAL;
+
+	ret = i40e_sw_ethertype_filter_del(pf, &node->input);
+
+	return ret;
+}
-- 
2.5.5

^ permalink raw reply related

* [PATCH v6 11/17] net/i40e: add flow destroy function
From: Beilei Xing @ 2017-01-05 15:46 UTC (permalink / raw)
  To: jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-1-git-send-email-beilei.xing@intel.com>

This patch adds i40e_flow_destroy function to destroy
a flow for users.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
---
 drivers/net/i40e/i40e_flow.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index cc1656a..4daaca0 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -68,6 +68,9 @@ static struct rte_flow *i40e_flow_create(struct rte_eth_dev *dev,
 					 const struct rte_flow_item pattern[],
 					 const struct rte_flow_action actions[],
 					 struct rte_flow_error *error);
+static int i40e_flow_destroy(struct rte_eth_dev *dev,
+			     struct rte_flow *flow,
+			     struct rte_flow_error *error);
 static int
 i40e_flow_parse_ethertype_pattern(struct rte_eth_dev *dev,
 				  const struct rte_flow_item *pattern,
@@ -117,6 +120,7 @@ static int i40e_flow_parse_tunnel_filter(struct rte_eth_dev *dev,
 const struct rte_flow_ops i40e_flow_ops = {
 	.validate = i40e_flow_validate,
 	.create = i40e_flow_create,
+	.destroy = i40e_flow_destroy,
 };
 
 union i40e_filter_t cons_filter;
@@ -1602,3 +1606,32 @@ i40e_flow_create(struct rte_eth_dev *dev,
 	rte_free(flow);
 	return NULL;
 }
+
+static int
+i40e_flow_destroy(struct rte_eth_dev *dev,
+		  struct rte_flow *flow,
+		  struct rte_flow_error *error)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_flow *pmd_flow = (struct i40e_flow *)flow;
+	enum rte_filter_type filter_type = pmd_flow->filter_type;
+	int ret = 0;
+
+	switch (filter_type) {
+	default:
+		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+			    filter_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	if (!ret) {
+		TAILQ_REMOVE(&pf->flow_list, pmd_flow, node);
+		rte_free(pmd_flow);
+	} else
+		rte_flow_error_set(error, -ret,
+				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				   "Failed to destroy flow.");
+
+	return ret;
+}
-- 
2.5.5

^ permalink raw reply related

* [PATCH v6 10/17] net/i40e: add flow create function
From: Beilei Xing @ 2017-01-05 15:46 UTC (permalink / raw)
  To: jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-1-git-send-email-beilei.xing@intel.com>

This patch adds i40e_flow_create function to create a
rule. It will check if a flow matches ethertype filter
or flow director filter or tunnel filter, if the flow
matches some kind of filter, then set the filter to HW.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
---
 drivers/net/i40e/i40e_ethdev.c | 16 ++++++---
 drivers/net/i40e/i40e_ethdev.h | 21 ++++++++++++
 drivers/net/i40e/i40e_fdir.c   |  2 +-
 drivers/net/i40e/i40e_flow.c   | 77 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 110 insertions(+), 6 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 81ed13e..52e3047 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -348,9 +348,6 @@ static int i40e_dev_udp_tunnel_port_add(struct rte_eth_dev *dev,
 static int i40e_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
 					struct rte_eth_udp_tunnel *udp_tunnel);
 static void i40e_filter_input_set_init(struct i40e_pf *pf);
-static int i40e_ethertype_filter_set(struct i40e_pf *pf,
-			struct rte_eth_ethertype_filter *filter,
-			bool add);
 static int i40e_ethertype_filter_handle(struct rte_eth_dev *dev,
 				enum rte_filter_op filter_op,
 				void *arg);
@@ -1230,6 +1227,8 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
 		goto err_fdir_hash_map_alloc;
 	}
 
+	TAILQ_INIT(&pf->flow_list);
+
 	return 0;
 
 err_fdir_hash_map_alloc:
@@ -1271,6 +1270,7 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
 	struct rte_intr_handle *intr_handle;
 	struct i40e_hw *hw;
 	struct i40e_filter_control_settings settings;
+	struct i40e_flow *p_flow;
 	struct i40e_ethertype_filter *p_ethertype;
 	struct i40e_tunnel_filter *p_tunnel;
 	struct i40e_fdir_filter *p_fdir;
@@ -1296,6 +1296,12 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
 	if (hw->adapter_stopped == 0)
 		i40e_dev_close(dev);
 
+	/* Remove all flows */
+	while ((p_flow = TAILQ_FIRST(&pf->flow_list))) {
+		TAILQ_REMOVE(&pf->flow_list, p_flow, node);
+		rte_free(p_flow);
+	}
+
 	/* Remove all ethertype director rules and hash */
 	if (ethertype_rule->hash_map)
 		rte_free(ethertype_rule->hash_map);
@@ -6621,7 +6627,7 @@ i40e_sw_tunnel_filter_del(struct i40e_pf *pf,
 	return 0;
 }
 
-static int
+int
 i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
 			struct rte_eth_tunnel_filter_conf *tunnel_filter,
 			uint8_t add)
@@ -8266,7 +8272,7 @@ i40e_sw_ethertype_filter_del(struct i40e_pf *pf,
  * Configure ethertype filter, which can director packet by filtering
  * with mac address and ether_type or only ether_type
  */
-static int
+int
 i40e_ethertype_filter_set(struct i40e_pf *pf,
 			struct rte_eth_ethertype_filter *filter,
 			bool add)
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 4597615..0088351 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -541,6 +541,17 @@ struct i40e_mirror_rule {
 TAILQ_HEAD(i40e_mirror_rule_list, i40e_mirror_rule);
 
 /*
+ * Struct to store flow created.
+ */
+struct i40e_flow {
+	TAILQ_ENTRY(i40e_flow) node;
+	enum rte_filter_type filter_type;
+	void *rule;
+};
+
+TAILQ_HEAD(i40e_flow_list, i40e_flow);
+
+/*
  * Structure to store private data specific for PF instance.
  */
 struct i40e_pf {
@@ -597,6 +608,7 @@ struct i40e_pf {
 	bool floating_veb; /* The flag to use the floating VEB */
 	/* The floating enable flag for the specific VF */
 	bool floating_veb_list[I40E_MAX_VF];
+	struct i40e_flow_list flow_list;
 };
 
 enum pending_msg {
@@ -772,6 +784,15 @@ i40e_sw_tunnel_filter_lookup(struct i40e_tunnel_rule *tunnel_rule,
 int i40e_sw_tunnel_filter_del(struct i40e_pf *pf,
 			      struct i40e_tunnel_filter_input *input);
 uint64_t i40e_get_default_input_set(uint16_t pctype);
+int i40e_ethertype_filter_set(struct i40e_pf *pf,
+			      struct rte_eth_ethertype_filter *filter,
+			      bool add);
+int i40e_add_del_fdir_filter(struct rte_eth_dev *dev,
+			     const struct rte_eth_fdir_filter *filter,
+			     bool add);
+int i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
+			       struct rte_eth_tunnel_filter_conf *tunnel_filter,
+			       uint8_t add);
 
 #define I40E_DEV_TO_PCI(eth_dev) \
 	RTE_DEV_TO_PCI((eth_dev)->device)
diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c
index f89dbc9..91d91aa 100644
--- a/drivers/net/i40e/i40e_fdir.c
+++ b/drivers/net/i40e/i40e_fdir.c
@@ -1099,7 +1099,7 @@ i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct rte_eth_fdir_input *input)
  * @filter: fdir filter entry
  * @add: 0 - delete, 1 - add
  */
-static int
+int
 i40e_add_del_fdir_filter(struct rte_eth_dev *dev,
 			    const struct rte_eth_fdir_filter *filter,
 			    bool add)
diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index ed87624..cc1656a 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -63,6 +63,11 @@ static int i40e_flow_validate(struct rte_eth_dev *dev,
 			      const struct rte_flow_item pattern[],
 			      const struct rte_flow_action actions[],
 			      struct rte_flow_error *error);
+static struct rte_flow *i40e_flow_create(struct rte_eth_dev *dev,
+					 const struct rte_flow_attr *attr,
+					 const struct rte_flow_item pattern[],
+					 const struct rte_flow_action actions[],
+					 struct rte_flow_error *error);
 static int
 i40e_flow_parse_ethertype_pattern(struct rte_eth_dev *dev,
 				  const struct rte_flow_item *pattern,
@@ -111,9 +116,11 @@ static int i40e_flow_parse_tunnel_filter(struct rte_eth_dev *dev,
 
 const struct rte_flow_ops i40e_flow_ops = {
 	.validate = i40e_flow_validate,
+	.create = i40e_flow_create,
 };
 
 union i40e_filter_t cons_filter;
+enum rte_filter_type cons_filter_type = RTE_ETH_FILTER_NONE;
 
 /* Pattern matched ethertype filter */
 static enum rte_flow_item_type pattern_ethertype[] = {
@@ -615,6 +622,8 @@ i40e_flow_parse_ethertype_filter(struct rte_eth_dev *dev,
 	if (ret)
 		return ret;
 
+	cons_filter_type = RTE_ETH_FILTER_ETHERTYPE;
+
 	return ret;
 }
 
@@ -1093,6 +1102,8 @@ i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev,
 	if (ret)
 		return ret;
 
+	cons_filter_type = RTE_ETH_FILTER_FDIR;
+
 	if (dev->data->dev_conf.fdir_conf.mode !=
 	    RTE_FDIR_MODE_PERFECT) {
 		rte_flow_error_set(error, ENOTSUP,
@@ -1454,6 +1465,8 @@ i40e_flow_parse_tunnel_filter(struct rte_eth_dev *dev,
 	if (ret)
 		return ret;
 
+	cons_filter_type = RTE_ETH_FILTER_TUNNEL;
+
 	return ret;
 }
 
@@ -1525,3 +1538,67 @@ i40e_flow_validate(struct rte_eth_dev *dev,
 
 	return ret;
 }
+
+static struct rte_flow *
+i40e_flow_create(struct rte_eth_dev *dev,
+		 const struct rte_flow_attr *attr,
+		 const struct rte_flow_item pattern[],
+		 const struct rte_flow_action actions[],
+		 struct rte_flow_error *error)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_flow *flow;
+	int ret;
+
+	flow = rte_zmalloc("i40e_flow", sizeof(struct i40e_flow), 0);
+	if (!flow) {
+		rte_flow_error_set(error, ENOMEM,
+				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				   "Failed to allocate memory");
+		return (struct rte_flow *)flow;
+	}
+
+	ret = i40e_flow_validate(dev, attr, pattern, actions, error);
+	if (ret < 0)
+		return NULL;
+
+	switch (cons_filter_type) {
+	case RTE_ETH_FILTER_ETHERTYPE:
+		ret = i40e_ethertype_filter_set(pf,
+					&cons_filter.ethertype_filter, 1);
+		if (ret)
+			goto free_flow;
+		flow->rule = TAILQ_LAST(&pf->ethertype.ethertype_list,
+					i40e_ethertype_filter_list);
+		break;
+	case RTE_ETH_FILTER_FDIR:
+		ret = i40e_add_del_fdir_filter(dev,
+				       &cons_filter.fdir_filter, 1);
+		if (ret)
+			goto free_flow;
+		flow->rule = TAILQ_LAST(&pf->fdir.fdir_list,
+					i40e_fdir_filter_list);
+		break;
+	case RTE_ETH_FILTER_TUNNEL:
+		ret = i40e_dev_tunnel_filter_set(pf,
+					 &cons_filter.tunnel_filter, 1);
+		if (ret)
+			goto free_flow;
+		flow->rule = TAILQ_LAST(&pf->tunnel.tunnel_list,
+					i40e_tunnel_filter_list);
+		break;
+	default:
+		goto free_flow;
+	}
+
+	flow->filter_type = cons_filter_type;
+	TAILQ_INSERT_TAIL(&pf->flow_list, flow, node);
+	return (struct rte_flow *)flow;
+
+free_flow:
+	rte_flow_error_set(error, -ret,
+			   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			   "Failed to create flow.");
+	rte_free(flow);
+	return NULL;
+}
-- 
2.5.5

^ permalink raw reply related

* [PATCH v6 09/17] net/i40e: parse tunnel filter
From: Beilei Xing @ 2017-01-05 15:46 UTC (permalink / raw)
  To: jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-1-git-send-email-beilei.xing@intel.com>

This patch adds i40e_flow_parse_tunnel_filter to check
if a rule is a tunnel rule according to items of the
flow pattern, and the function also gets the tunnel info.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
---
 drivers/net/i40e/i40e_flow.c | 412 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 412 insertions(+)

diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index 2eead93..ed87624 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -55,6 +55,8 @@
 #define I40E_IPV4_TC_SHIFT	4
 #define I40E_IPV6_TC_MASK	(0x00FF << I40E_IPV4_TC_SHIFT)
 #define I40E_IPV6_FRAG_HEADER	44
+#define I40E_TENANT_ARRAY_NUM	3
+#define I40E_TCI_MASK		0xFFFF
 
 static int i40e_flow_validate(struct rte_eth_dev *dev,
 			      const struct rte_flow_attr *attr,
@@ -78,6 +80,14 @@ static int i40e_flow_parse_fdir_action(struct rte_eth_dev *dev,
 				       const struct rte_flow_action *actions,
 				       struct rte_flow_error *error,
 				       struct rte_eth_fdir_filter *filter);
+static int i40e_flow_parse_tunnel_pattern(__rte_unused struct rte_eth_dev *dev,
+				  const struct rte_flow_item *pattern,
+				  struct rte_flow_error *error,
+				  struct rte_eth_tunnel_filter_conf *filter);
+static int i40e_flow_parse_tunnel_action(struct rte_eth_dev *dev,
+				 const struct rte_flow_action *actions,
+				 struct rte_flow_error *error,
+				 struct rte_eth_tunnel_filter_conf *filter);
 static int i40e_flow_parse_attr(const struct rte_flow_attr *attr,
 				struct rte_flow_error *error);
 static int i40e_flow_parse_ethertype_filter(struct rte_eth_dev *dev,
@@ -92,6 +102,12 @@ static int i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev,
 				       const struct rte_flow_action actions[],
 				       struct rte_flow_error *error,
 				       union i40e_filter_t *filter);
+static int i40e_flow_parse_tunnel_filter(struct rte_eth_dev *dev,
+					 const struct rte_flow_attr *attr,
+					 const struct rte_flow_item pattern[],
+					 const struct rte_flow_action actions[],
+					 struct rte_flow_error *error,
+					 union i40e_filter_t *filter);
 
 const struct rte_flow_ops i40e_flow_ops = {
 	.validate = i40e_flow_validate,
@@ -206,6 +222,45 @@ static enum rte_flow_item_type pattern_fdir_ipv6_sctp_ext[] = {
 	RTE_FLOW_ITEM_TYPE_END,
 };
 
+/* Pattern matched tunnel filter */
+static enum rte_flow_item_type pattern_vxlan_1[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV4,
+	RTE_FLOW_ITEM_TYPE_UDP,
+	RTE_FLOW_ITEM_TYPE_VXLAN,
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_vxlan_2[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV6,
+	RTE_FLOW_ITEM_TYPE_UDP,
+	RTE_FLOW_ITEM_TYPE_VXLAN,
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_vxlan_3[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV4,
+	RTE_FLOW_ITEM_TYPE_UDP,
+	RTE_FLOW_ITEM_TYPE_VXLAN,
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_VLAN,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_vxlan_4[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV6,
+	RTE_FLOW_ITEM_TYPE_UDP,
+	RTE_FLOW_ITEM_TYPE_VXLAN,
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_VLAN,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
 static struct i40e_valid_pattern i40e_supported_patterns[] = {
 	/* Ethertype */
 	{ pattern_ethertype, i40e_flow_parse_ethertype_filter },
@@ -226,6 +281,11 @@ static struct i40e_valid_pattern i40e_supported_patterns[] = {
 	{ pattern_fdir_ipv6_tcp_ext, i40e_flow_parse_fdir_filter },
 	{ pattern_fdir_ipv6_sctp, i40e_flow_parse_fdir_filter },
 	{ pattern_fdir_ipv6_sctp_ext, i40e_flow_parse_fdir_filter },
+	/* tunnel */
+	{ pattern_vxlan_1, i40e_flow_parse_tunnel_filter },
+	{ pattern_vxlan_2, i40e_flow_parse_tunnel_filter },
+	{ pattern_vxlan_3, i40e_flow_parse_tunnel_filter },
+	{ pattern_vxlan_4, i40e_flow_parse_tunnel_filter },
 };
 
 #define NEXT_ITEM_OF_ACTION(act, actions, index)                        \
@@ -1045,6 +1105,358 @@ i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/* Parse to get the action info of a tunnle filter
+ * Tunnel action only supports QUEUE.
+ */
+static int
+i40e_flow_parse_tunnel_action(struct rte_eth_dev *dev,
+			      const struct rte_flow_action *actions,
+			      struct rte_flow_error *error,
+			      struct rte_eth_tunnel_filter_conf *filter)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	const struct rte_flow_action *act;
+	const struct rte_flow_action_queue *act_q;
+	uint32_t index = 0;
+
+	/* Check if the first non-void action is QUEUE. */
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	if (act->type != RTE_FLOW_ACTION_TYPE_QUEUE) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				   act, "Not supported action.");
+		return -rte_errno;
+	}
+
+	act_q = (const struct rte_flow_action_queue *)act->conf;
+	filter->queue_id = act_q->index;
+	if (filter->queue_id >= pf->dev_data->nb_rx_queues) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ACTION,
+				   act, "Invalid queue ID for tunnel filter");
+		return -rte_errno;
+	}
+
+	/* Check if the next non-void item is END */
+	index++;
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				   act, "Not supported action.");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
+static int
+i40e_check_tenant_id_mask(const uint8_t *mask)
+{
+	uint32_t j;
+	int is_masked = 0;
+
+	for (j = 0; j < I40E_TENANT_ARRAY_NUM; j++) {
+		if (*(mask + j) == UINT8_MAX) {
+			if (j > 0 && (*(mask + j) != *(mask + j - 1)))
+				return -EINVAL;
+			is_masked = 0;
+		} else if (*(mask + j) == 0) {
+			if (j > 0 && (*(mask + j) != *(mask + j - 1)))
+				return -EINVAL;
+			is_masked = 1;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	return is_masked;
+}
+
+/* 1. Last in item should be NULL as range is not supported.
+ * 2. Supported filter types: IMAC_IVLAN_TENID, IMAC_IVLAN,
+ *    IMAC_TENID, OMAC_TENID_IMAC and IMAC.
+ * 3. Mask of fields which need to be matched should be
+ *    filled with 1.
+ * 4. Mask of fields which needn't to be matched should be
+ *    filled with 0.
+ */
+static int
+i40e_flow_parse_vxlan_pattern(const struct rte_flow_item *pattern,
+			      struct rte_flow_error *error,
+			      struct rte_eth_tunnel_filter_conf *filter)
+{
+	const struct rte_flow_item *item = pattern;
+	const struct rte_flow_item_eth *eth_spec;
+	const struct rte_flow_item_eth *eth_mask;
+	const struct rte_flow_item_eth *o_eth_spec = NULL;
+	const struct rte_flow_item_eth *o_eth_mask = NULL;
+	const struct rte_flow_item_vxlan *vxlan_spec = NULL;
+	const struct rte_flow_item_vxlan *vxlan_mask = NULL;
+	const struct rte_flow_item_eth *i_eth_spec = NULL;
+	const struct rte_flow_item_eth *i_eth_mask = NULL;
+	const struct rte_flow_item_vlan *vlan_spec = NULL;
+	const struct rte_flow_item_vlan *vlan_mask = NULL;
+	bool is_vni_masked = 0;
+	enum rte_flow_item_type item_type;
+	bool vxlan_flag = 0;
+
+	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
+		if (item->last) {
+			rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ITEM,
+					   item,
+					   "Not support range");
+			return -rte_errno;
+		}
+		item_type = item->type;
+		switch (item_type) {
+		case RTE_FLOW_ITEM_TYPE_ETH:
+			eth_spec = (const struct rte_flow_item_eth *)item->spec;
+			eth_mask = (const struct rte_flow_item_eth *)item->mask;
+			if ((!eth_spec && eth_mask) ||
+			    (eth_spec && !eth_mask)) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid ether spec/mask");
+				return -rte_errno;
+			}
+
+			if (eth_spec && eth_mask) {
+				/* DST address of inner MAC shouldn't be masked.
+				 * SRC address of Inner MAC should be masked.
+				 */
+				if (!is_broadcast_ether_addr(&eth_mask->dst) ||
+				    !is_zero_ether_addr(&eth_mask->src) ||
+				    eth_mask->type) {
+					rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid ether spec/mask");
+					return -rte_errno;
+				}
+
+				if (!vxlan_flag)
+					rte_memcpy(&filter->outer_mac,
+						   &eth_spec->dst,
+						   ETHER_ADDR_LEN);
+				else
+					rte_memcpy(&filter->inner_mac,
+						   &eth_spec->dst,
+						   ETHER_ADDR_LEN);
+			}
+
+			if (!vxlan_flag) {
+				o_eth_spec = eth_spec;
+				o_eth_mask = eth_mask;
+			} else {
+				i_eth_spec = eth_spec;
+				i_eth_mask = eth_mask;
+			}
+
+			break;
+		case RTE_FLOW_ITEM_TYPE_VLAN:
+			vlan_spec =
+				(const struct rte_flow_item_vlan *)item->spec;
+			vlan_mask =
+				(const struct rte_flow_item_vlan *)item->mask;
+			if (vxlan_flag) {
+				vlan_spec =
+				(const struct rte_flow_item_vlan *)item->spec;
+				vlan_mask =
+				(const struct rte_flow_item_vlan *)item->mask;
+				if (!(vlan_spec && vlan_mask)) {
+					rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid vlan item");
+					return -rte_errno;
+				}
+			} else {
+				if (vlan_spec || vlan_mask)
+					rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid vlan item");
+				return -rte_errno;
+			}
+			break;
+		case RTE_FLOW_ITEM_TYPE_IPV4:
+		case RTE_FLOW_ITEM_TYPE_IPV6:
+		case RTE_FLOW_ITEM_TYPE_UDP:
+			/* IPv4/IPv6/UDP are used to describe protocol,
+			 * spec amd mask should be NULL.
+			 */
+			if (item->spec || item->mask) {
+				rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ITEM,
+					   item,
+					   "Invalid IPv4 item");
+				return -rte_errno;
+			}
+			break;
+		case RTE_FLOW_ITEM_TYPE_VXLAN:
+			vxlan_spec =
+				(const struct rte_flow_item_vxlan *)item->spec;
+			vxlan_mask =
+				(const struct rte_flow_item_vxlan *)item->mask;
+			/* Check if VXLAN item is used to describe protocol.
+			 * If yes, both spec and mask should be NULL.
+			 * If no, either spec or mask shouldn't be NULL.
+			 */
+			if ((!vxlan_spec && vxlan_mask) ||
+			    (vxlan_spec && !vxlan_mask)) {
+				rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ITEM,
+					   item,
+					   "Invalid VXLAN item");
+				return -rte_errno;
+			}
+
+			/* Check if VNI is masked. */
+			if (vxlan_mask) {
+				is_vni_masked =
+				i40e_check_tenant_id_mask(vxlan_mask->vni);
+				if (is_vni_masked < 0) {
+					rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid VNI mask");
+					return -rte_errno;
+				}
+			}
+			vxlan_flag = 1;
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* Check specification and mask to get the filter type */
+	if (vlan_spec && vlan_mask &&
+	    (vlan_mask->tci == rte_cpu_to_be_16(I40E_TCI_MASK))) {
+		/* If there's inner vlan */
+		filter->inner_vlan = rte_be_to_cpu_16(vlan_spec->tci)
+			& I40E_TCI_MASK;
+		if (vxlan_spec && vxlan_mask && !is_vni_masked) {
+			/* If there's vxlan */
+			rte_memcpy(&filter->tenant_id, vxlan_spec->vni,
+				   RTE_DIM(vxlan_spec->vni));
+			if (!o_eth_spec && !o_eth_mask &&
+				i_eth_spec && i_eth_mask)
+				filter->filter_type =
+					RTE_TUNNEL_FILTER_IMAC_IVLAN_TENID;
+			else {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   NULL,
+						   "Invalid filter type");
+				return -rte_errno;
+			}
+		} else if (!vxlan_spec && !vxlan_mask) {
+			/* If there's no vxlan */
+			if (!o_eth_spec && !o_eth_mask &&
+				i_eth_spec && i_eth_mask)
+				filter->filter_type =
+					RTE_TUNNEL_FILTER_IMAC_IVLAN;
+			else {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   NULL,
+						   "Invalid filter type");
+				return -rte_errno;
+			}
+		} else {
+			rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ITEM,
+					   NULL,
+					   "Invalid filter type");
+			return -rte_errno;
+		}
+	} else if ((!vlan_spec && !vlan_mask) ||
+		   (vlan_spec && vlan_mask && vlan_mask->tci == 0x0)) {
+		/* If there's no inner vlan */
+		if (vxlan_spec && vxlan_mask && !is_vni_masked) {
+			/* If there's vxlan */
+			rte_memcpy(&filter->tenant_id, vxlan_spec->vni,
+				   RTE_DIM(vxlan_spec->vni));
+			if (!o_eth_spec && !o_eth_mask &&
+				i_eth_spec && i_eth_mask)
+				filter->filter_type =
+					RTE_TUNNEL_FILTER_IMAC_TENID;
+			else if (o_eth_spec && o_eth_mask &&
+				i_eth_spec && i_eth_mask)
+				filter->filter_type =
+					RTE_TUNNEL_FILTER_OMAC_TENID_IMAC;
+		} else if (!vxlan_spec && !vxlan_mask) {
+			/* If there's no vxlan */
+			if (!o_eth_spec && !o_eth_mask &&
+				i_eth_spec && i_eth_mask) {
+				filter->filter_type = ETH_TUNNEL_FILTER_IMAC;
+			} else {
+				rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+					   "Invalid filter type");
+				return -rte_errno;
+			}
+		} else {
+			rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+					   "Invalid filter type");
+			return -rte_errno;
+		}
+	} else {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+				   "Not supported by tunnel filter.");
+		return -rte_errno;
+	}
+
+	filter->tunnel_type = RTE_TUNNEL_TYPE_VXLAN;
+
+	return 0;
+}
+
+static int
+i40e_flow_parse_tunnel_pattern(__rte_unused struct rte_eth_dev *dev,
+			       const struct rte_flow_item *pattern,
+			       struct rte_flow_error *error,
+			       struct rte_eth_tunnel_filter_conf *filter)
+{
+	int ret;
+
+	ret = i40e_flow_parse_vxlan_pattern(pattern, error, filter);
+
+	return ret;
+}
+
+static int
+i40e_flow_parse_tunnel_filter(struct rte_eth_dev *dev,
+			      const struct rte_flow_attr *attr,
+			      const struct rte_flow_item pattern[],
+			      const struct rte_flow_action actions[],
+			      struct rte_flow_error *error,
+			      union i40e_filter_t *filter)
+{
+	struct rte_eth_tunnel_filter_conf *tunnel_filter =
+		&filter->tunnel_filter;
+	int ret;
+
+	ret = i40e_flow_parse_tunnel_pattern(dev, pattern,
+					     error, tunnel_filter);
+	if (ret)
+		return ret;
+
+	ret = i40e_flow_parse_tunnel_action(dev, actions, error, tunnel_filter);
+	if (ret)
+		return ret;
+
+	ret = i40e_flow_parse_attr(attr, error);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
 static int
 i40e_flow_validate(struct rte_eth_dev *dev,
 		   const struct rte_flow_attr *attr,
-- 
2.5.5

^ permalink raw reply related

* [PATCH v6 08/17] net/i40e: parse flow director filter
From: Beilei Xing @ 2017-01-05 15:46 UTC (permalink / raw)
  To: jingjing.wu, helin.zhang; +Cc: dev
In-Reply-To: <1483631170-16681-1-git-send-email-beilei.xing@intel.com>

This patch adds i40e_flow_parse_fdir_filter to check
if a rule is a flow director rule according to the
flow pattern, and the function also gets the flow
director info.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
---
 drivers/net/i40e/i40e_ethdev.c |  56 +---
 drivers/net/i40e/i40e_ethdev.h |  55 ++++
 drivers/net/i40e/i40e_flow.c   | 623 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 679 insertions(+), 55 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 01338ca..81ed13e 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -139,60 +139,6 @@
 #define I40E_DEFAULT_DCB_APP_NUM    1
 #define I40E_DEFAULT_DCB_APP_PRIO   3
 
-#define I40E_INSET_NONE            0x00000000000000000ULL
-
-/* bit0 ~ bit 7 */
-#define I40E_INSET_DMAC            0x0000000000000001ULL
-#define I40E_INSET_SMAC            0x0000000000000002ULL
-#define I40E_INSET_VLAN_OUTER      0x0000000000000004ULL
-#define I40E_INSET_VLAN_INNER      0x0000000000000008ULL
-#define I40E_INSET_VLAN_TUNNEL     0x0000000000000010ULL
-
-/* bit 8 ~ bit 15 */
-#define I40E_INSET_IPV4_SRC        0x0000000000000100ULL
-#define I40E_INSET_IPV4_DST        0x0000000000000200ULL
-#define I40E_INSET_IPV6_SRC        0x0000000000000400ULL
-#define I40E_INSET_IPV6_DST        0x0000000000000800ULL
-#define I40E_INSET_SRC_PORT        0x0000000000001000ULL
-#define I40E_INSET_DST_PORT        0x0000000000002000ULL
-#define I40E_INSET_SCTP_VT         0x0000000000004000ULL
-
-/* bit 16 ~ bit 31 */
-#define I40E_INSET_IPV4_TOS        0x0000000000010000ULL
-#define I40E_INSET_IPV4_PROTO      0x0000000000020000ULL
-#define I40E_INSET_IPV4_TTL        0x0000000000040000ULL
-#define I40E_INSET_IPV6_TC         0x0000000000080000ULL
-#define I40E_INSET_IPV6_FLOW       0x0000000000100000ULL
-#define I40E_INSET_IPV6_NEXT_HDR   0x0000000000200000ULL
-#define I40E_INSET_IPV6_HOP_LIMIT  0x0000000000400000ULL
-#define I40E_INSET_TCP_FLAGS       0x0000000000800000ULL
-
-/* bit 32 ~ bit 47, tunnel fields */
-#define I40E_INSET_TUNNEL_IPV4_DST       0x0000000100000000ULL
-#define I40E_INSET_TUNNEL_IPV6_DST       0x0000000200000000ULL
-#define I40E_INSET_TUNNEL_DMAC           0x0000000400000000ULL
-#define I40E_INSET_TUNNEL_SRC_PORT       0x0000000800000000ULL
-#define I40E_INSET_TUNNEL_DST_PORT       0x0000001000000000ULL
-#define I40E_INSET_TUNNEL_ID             0x0000002000000000ULL
-
-/* bit 48 ~ bit 55 */
-#define I40E_INSET_LAST_ETHER_TYPE 0x0001000000000000ULL
-
-/* bit 56 ~ bit 63, Flex Payload */
-#define I40E_INSET_FLEX_PAYLOAD_W1 0x0100000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W2 0x0200000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W3 0x0400000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W4 0x0800000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W5 0x1000000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W6 0x2000000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W7 0x4000000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W8 0x8000000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD \
-	(I40E_INSET_FLEX_PAYLOAD_W1 | I40E_INSET_FLEX_PAYLOAD_W2 | \
-	I40E_INSET_FLEX_PAYLOAD_W3 | I40E_INSET_FLEX_PAYLOAD_W4 | \
-	I40E_INSET_FLEX_PAYLOAD_W5 | I40E_INSET_FLEX_PAYLOAD_W6 | \
-	I40E_INSET_FLEX_PAYLOAD_W7 | I40E_INSET_FLEX_PAYLOAD_W8)
-
 /**
  * Below are values for writing un-exposed registers suggested
  * by silicon experts
@@ -7627,7 +7573,7 @@ i40e_validate_input_set(enum i40e_filter_pctype pctype,
 }
 
 /* default input set fields combination per pctype */
-static uint64_t
+uint64_t
 i40e_get_default_input_set(uint16_t pctype)
 {
 	static const uint64_t default_inset_table[] = {
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 00c2a0a..4597615 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -195,6 +195,60 @@ enum i40e_flxpld_layer_idx {
 #define I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_MASK  \
 	I40E_MASK(0xFFFF, I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_SHIFT)
 
+#define I40E_INSET_NONE            0x00000000000000000ULL
+
+/* bit0 ~ bit 7 */
+#define I40E_INSET_DMAC            0x0000000000000001ULL
+#define I40E_INSET_SMAC            0x0000000000000002ULL
+#define I40E_INSET_VLAN_OUTER      0x0000000000000004ULL
+#define I40E_INSET_VLAN_INNER      0x0000000000000008ULL
+#define I40E_INSET_VLAN_TUNNEL     0x0000000000000010ULL
+
+/* bit 8 ~ bit 15 */
+#define I40E_INSET_IPV4_SRC        0x0000000000000100ULL
+#define I40E_INSET_IPV4_DST        0x0000000000000200ULL
+#define I40E_INSET_IPV6_SRC        0x0000000000000400ULL
+#define I40E_INSET_IPV6_DST        0x0000000000000800ULL
+#define I40E_INSET_SRC_PORT        0x0000000000001000ULL
+#define I40E_INSET_DST_PORT        0x0000000000002000ULL
+#define I40E_INSET_SCTP_VT         0x0000000000004000ULL
+
+/* bit 16 ~ bit 31 */
+#define I40E_INSET_IPV4_TOS        0x0000000000010000ULL
+#define I40E_INSET_IPV4_PROTO      0x0000000000020000ULL
+#define I40E_INSET_IPV4_TTL        0x0000000000040000ULL
+#define I40E_INSET_IPV6_TC         0x0000000000080000ULL
+#define I40E_INSET_IPV6_FLOW       0x0000000000100000ULL
+#define I40E_INSET_IPV6_NEXT_HDR   0x0000000000200000ULL
+#define I40E_INSET_IPV6_HOP_LIMIT  0x0000000000400000ULL
+#define I40E_INSET_TCP_FLAGS       0x0000000000800000ULL
+
+/* bit 32 ~ bit 47, tunnel fields */
+#define I40E_INSET_TUNNEL_IPV4_DST       0x0000000100000000ULL
+#define I40E_INSET_TUNNEL_IPV6_DST       0x0000000200000000ULL
+#define I40E_INSET_TUNNEL_DMAC           0x0000000400000000ULL
+#define I40E_INSET_TUNNEL_SRC_PORT       0x0000000800000000ULL
+#define I40E_INSET_TUNNEL_DST_PORT       0x0000001000000000ULL
+#define I40E_INSET_TUNNEL_ID             0x0000002000000000ULL
+
+/* bit 48 ~ bit 55 */
+#define I40E_INSET_LAST_ETHER_TYPE 0x0001000000000000ULL
+
+/* bit 56 ~ bit 63, Flex Payload */
+#define I40E_INSET_FLEX_PAYLOAD_W1 0x0100000000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W2 0x0200000000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W3 0x0400000000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W4 0x0800000000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W5 0x1000000000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W6 0x2000000000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W7 0x4000000000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W8 0x8000000000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD \
+	(I40E_INSET_FLEX_PAYLOAD_W1 | I40E_INSET_FLEX_PAYLOAD_W2 | \
+	I40E_INSET_FLEX_PAYLOAD_W3 | I40E_INSET_FLEX_PAYLOAD_W4 | \
+	I40E_INSET_FLEX_PAYLOAD_W5 | I40E_INSET_FLEX_PAYLOAD_W6 | \
+	I40E_INSET_FLEX_PAYLOAD_W7 | I40E_INSET_FLEX_PAYLOAD_W8)
+
 struct i40e_adapter;
 
 /**
@@ -717,6 +771,7 @@ i40e_sw_tunnel_filter_lookup(struct i40e_tunnel_rule *tunnel_rule,
 			     const struct i40e_tunnel_filter_input *input);
 int i40e_sw_tunnel_filter_del(struct i40e_pf *pf,
 			      struct i40e_tunnel_filter_input *input);
+uint64_t i40e_get_default_input_set(uint16_t pctype);
 
 #define I40E_DEV_TO_PCI(eth_dev) \
 	RTE_DEV_TO_PCI((eth_dev)->device)
diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index 5ca7a42..2eead93 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -52,6 +52,10 @@
 #include "base/i40e_prototype.h"
 #include "i40e_ethdev.h"
 
+#define I40E_IPV4_TC_SHIFT	4
+#define I40E_IPV6_TC_MASK	(0x00FF << I40E_IPV4_TC_SHIFT)
+#define I40E_IPV6_FRAG_HEADER	44
+
 static int i40e_flow_validate(struct rte_eth_dev *dev,
 			      const struct rte_flow_attr *attr,
 			      const struct rte_flow_item pattern[],
@@ -66,6 +70,14 @@ static int i40e_flow_parse_ethertype_action(struct rte_eth_dev *dev,
 				    const struct rte_flow_action *actions,
 				    struct rte_flow_error *error,
 				    struct rte_eth_ethertype_filter *filter);
+static int i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
+					const struct rte_flow_item *pattern,
+					struct rte_flow_error *error,
+					struct rte_eth_fdir_filter *filter);
+static int i40e_flow_parse_fdir_action(struct rte_eth_dev *dev,
+				       const struct rte_flow_action *actions,
+				       struct rte_flow_error *error,
+				       struct rte_eth_fdir_filter *filter);
 static int i40e_flow_parse_attr(const struct rte_flow_attr *attr,
 				struct rte_flow_error *error);
 static int i40e_flow_parse_ethertype_filter(struct rte_eth_dev *dev,
@@ -74,6 +86,12 @@ static int i40e_flow_parse_ethertype_filter(struct rte_eth_dev *dev,
 				    const struct rte_flow_action actions[],
 				    struct rte_flow_error *error,
 				    union i40e_filter_t *filter);
+static int i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev,
+				       const struct rte_flow_attr *attr,
+				       const struct rte_flow_item pattern[],
+				       const struct rte_flow_action actions[],
+				       struct rte_flow_error *error,
+				       union i40e_filter_t *filter);
 
 const struct rte_flow_ops i40e_flow_ops = {
 	.validate = i40e_flow_validate,
@@ -87,9 +105,127 @@ static enum rte_flow_item_type pattern_ethertype[] = {
 	RTE_FLOW_ITEM_TYPE_END,
 };
 
+/* Pattern matched flow director filter */
+static enum rte_flow_item_type pattern_fdir_ipv4[] = {
+	RTE_FLOW_ITEM_TYPE_IPV4,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv4_ext[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV4,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv4_udp[] = {
+	RTE_FLOW_ITEM_TYPE_IPV4,
+	RTE_FLOW_ITEM_TYPE_UDP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv4_udp_ext[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV4,
+	RTE_FLOW_ITEM_TYPE_UDP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv4_tcp[] = {
+	RTE_FLOW_ITEM_TYPE_IPV4,
+	RTE_FLOW_ITEM_TYPE_TCP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv4_tcp_ext[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV4,
+	RTE_FLOW_ITEM_TYPE_TCP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv4_sctp[] = {
+	RTE_FLOW_ITEM_TYPE_IPV4,
+	RTE_FLOW_ITEM_TYPE_SCTP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv4_sctp_ext[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV4,
+	RTE_FLOW_ITEM_TYPE_SCTP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv6[] = {
+	RTE_FLOW_ITEM_TYPE_IPV6,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv6_ext[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV6,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv6_udp[] = {
+	RTE_FLOW_ITEM_TYPE_IPV6,
+	RTE_FLOW_ITEM_TYPE_UDP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv6_udp_ext[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV6,
+	RTE_FLOW_ITEM_TYPE_UDP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv6_tcp[] = {
+	RTE_FLOW_ITEM_TYPE_IPV6,
+	RTE_FLOW_ITEM_TYPE_TCP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv6_tcp_ext[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV6,
+	RTE_FLOW_ITEM_TYPE_TCP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv6_sctp[] = {
+	RTE_FLOW_ITEM_TYPE_IPV6,
+	RTE_FLOW_ITEM_TYPE_SCTP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_fdir_ipv6_sctp_ext[] = {
+	RTE_FLOW_ITEM_TYPE_ETH,
+	RTE_FLOW_ITEM_TYPE_IPV6,
+	RTE_FLOW_ITEM_TYPE_SCTP,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
 static struct i40e_valid_pattern i40e_supported_patterns[] = {
 	/* Ethertype */
 	{ pattern_ethertype, i40e_flow_parse_ethertype_filter },
+	/* FDIR */
+	{ pattern_fdir_ipv4, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv4_ext, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv4_udp, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv4_udp_ext, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv4_tcp, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv4_tcp_ext, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv4_sctp, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv4_sctp_ext, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv6, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv6_ext, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv6_udp, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv6_udp_ext, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv6_tcp, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv6_tcp_ext, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv6_sctp, i40e_flow_parse_fdir_filter },
+	{ pattern_fdir_ipv6_sctp_ext, i40e_flow_parse_fdir_filter },
 };
 
 #define NEXT_ITEM_OF_ACTION(act, actions, index)                        \
@@ -422,6 +558,493 @@ i40e_flow_parse_ethertype_filter(struct rte_eth_dev *dev,
 	return ret;
 }
 
+/* 1. Last in item should be NULL as range is not supported.
+ * 2. Supported flow type and input set: refer to array
+ *    default_inset_table in i40e_ethdev.c.
+ * 3. Mask of fields which need to be matched should be
+ *    filled with 1.
+ * 4. Mask of fields which needn't to be matched should be
+ *    filled with 0.
+ */
+static int
+i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
+			     const struct rte_flow_item *pattern,
+			     struct rte_flow_error *error,
+			     struct rte_eth_fdir_filter *filter)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	const struct rte_flow_item *item = pattern;
+	const struct rte_flow_item_eth *eth_spec, *eth_mask;
+	const struct rte_flow_item_ipv4 *ipv4_spec, *ipv4_mask;
+	const struct rte_flow_item_ipv6 *ipv6_spec, *ipv6_mask;
+	const struct rte_flow_item_tcp *tcp_spec, *tcp_mask;
+	const struct rte_flow_item_udp *udp_spec, *udp_mask;
+	const struct rte_flow_item_sctp *sctp_spec, *sctp_mask;
+	const struct rte_flow_item_vf *vf_spec;
+	uint32_t flow_type = RTE_ETH_FLOW_UNKNOWN;
+	enum i40e_filter_pctype pctype;
+	uint64_t input_set = I40E_INSET_NONE;
+	uint16_t flag_offset;
+	enum rte_flow_item_type item_type;
+	enum rte_flow_item_type l3 = RTE_FLOW_ITEM_TYPE_END;
+	uint32_t j;
+
+	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
+		if (item->last) {
+			rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ITEM,
+					   item,
+					   "Not support range");
+			return -rte_errno;
+		}
+		item_type = item->type;
+		switch (item_type) {
+		case RTE_FLOW_ITEM_TYPE_ETH:
+			eth_spec = (const struct rte_flow_item_eth *)item->spec;
+			eth_mask = (const struct rte_flow_item_eth *)item->mask;
+			if (eth_spec || eth_mask) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid ETH spec/mask");
+				return -rte_errno;
+			}
+			break;
+		case RTE_FLOW_ITEM_TYPE_IPV4:
+			l3 = RTE_FLOW_ITEM_TYPE_IPV4;
+			ipv4_spec =
+				(const struct rte_flow_item_ipv4 *)item->spec;
+			ipv4_mask =
+				(const struct rte_flow_item_ipv4 *)item->mask;
+			if (!ipv4_spec || !ipv4_mask) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "NULL IPv4 spec/mask");
+				return -rte_errno;
+			}
+
+			/* Check IPv4 mask and update input set */
+			if (ipv4_mask->hdr.version_ihl ||
+			    ipv4_mask->hdr.total_length ||
+			    ipv4_mask->hdr.packet_id ||
+			    ipv4_mask->hdr.fragment_offset ||
+			    ipv4_mask->hdr.hdr_checksum) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid IPv4 mask.");
+				return -rte_errno;
+			}
+
+			if (ipv4_mask->hdr.src_addr == UINT32_MAX)
+				input_set |= I40E_INSET_IPV4_SRC;
+			if (ipv4_mask->hdr.dst_addr == UINT32_MAX)
+				input_set |= I40E_INSET_IPV4_DST;
+			if (ipv4_mask->hdr.type_of_service == UINT8_MAX)
+				input_set |= I40E_INSET_IPV4_TOS;
+			if (ipv4_mask->hdr.time_to_live == UINT8_MAX)
+				input_set |= I40E_INSET_IPV4_TTL;
+			if (ipv4_mask->hdr.next_proto_id == UINT8_MAX)
+				input_set |= I40E_INSET_IPV4_PROTO;
+
+			/* Get filter info */
+			flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_OTHER;
+			/* Check if it is fragment. */
+			flag_offset =
+			      rte_be_to_cpu_16(ipv4_spec->hdr.fragment_offset);
+			if (flag_offset & IPV4_HDR_OFFSET_MASK ||
+			    flag_offset & IPV4_HDR_MF_FLAG)
+				flow_type = RTE_ETH_FLOW_FRAG_IPV4;
+
+			/* Get the filter info */
+			filter->input.flow.ip4_flow.proto =
+				ipv4_spec->hdr.next_proto_id;
+			filter->input.flow.ip4_flow.tos =
+				ipv4_spec->hdr.type_of_service;
+			filter->input.flow.ip4_flow.ttl =
+				ipv4_spec->hdr.time_to_live;
+			filter->input.flow.ip4_flow.src_ip =
+				ipv4_spec->hdr.src_addr;
+			filter->input.flow.ip4_flow.dst_ip =
+				ipv4_spec->hdr.dst_addr;
+
+			break;
+		case RTE_FLOW_ITEM_TYPE_IPV6:
+			l3 = RTE_FLOW_ITEM_TYPE_IPV6;
+			ipv6_spec =
+				(const struct rte_flow_item_ipv6 *)item->spec;
+			ipv6_mask =
+				(const struct rte_flow_item_ipv6 *)item->mask;
+			if (!ipv6_spec || !ipv6_mask) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "NULL IPv6 spec/mask");
+				return -rte_errno;
+			}
+
+			/* Check IPv6 mask and update input set */
+			if (ipv6_mask->hdr.payload_len) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid IPv6 mask");
+				return -rte_errno;
+			}
+
+			/* SCR and DST address of IPv6 shouldn't be masked */
+			for (j = 0; j < RTE_DIM(ipv6_mask->hdr.src_addr); j++) {
+				if (ipv6_mask->hdr.src_addr[j] != UINT8_MAX ||
+				    ipv6_mask->hdr.dst_addr[j] != UINT8_MAX) {
+					rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid IPv6 mask");
+					return -rte_errno;
+				}
+			}
+
+			input_set |= I40E_INSET_IPV6_SRC;
+			input_set |= I40E_INSET_IPV6_DST;
+
+			if ((ipv6_mask->hdr.vtc_flow &
+			     rte_cpu_to_be_16(I40E_IPV6_TC_MASK))
+			    == rte_cpu_to_be_16(I40E_IPV6_TC_MASK))
+				input_set |= I40E_INSET_IPV6_TC;
+			if (ipv6_mask->hdr.proto == UINT8_MAX)
+				input_set |= I40E_INSET_IPV6_NEXT_HDR;
+			if (ipv6_mask->hdr.hop_limits == UINT8_MAX)
+				input_set |= I40E_INSET_IPV6_HOP_LIMIT;
+
+			/* Get filter info */
+			filter->input.flow.ipv6_flow.tc =
+				(uint8_t)(ipv6_spec->hdr.vtc_flow <<
+					  I40E_IPV4_TC_SHIFT);
+			filter->input.flow.ipv6_flow.proto =
+				ipv6_spec->hdr.proto;
+			filter->input.flow.ipv6_flow.hop_limits =
+				ipv6_spec->hdr.hop_limits;
+
+			rte_memcpy(filter->input.flow.ipv6_flow.src_ip,
+				   ipv6_spec->hdr.src_addr, 16);
+			rte_memcpy(filter->input.flow.ipv6_flow.dst_ip,
+				   ipv6_spec->hdr.dst_addr, 16);
+
+			/* Check if it is fragment. */
+			if (ipv6_spec->hdr.proto == I40E_IPV6_FRAG_HEADER)
+				flow_type = RTE_ETH_FLOW_FRAG_IPV6;
+			else
+				flow_type = RTE_ETH_FLOW_NONFRAG_IPV6_OTHER;
+			break;
+		case RTE_FLOW_ITEM_TYPE_TCP:
+			tcp_spec = (const struct rte_flow_item_tcp *)item->spec;
+			tcp_mask = (const struct rte_flow_item_tcp *)item->mask;
+			if (!tcp_spec || !tcp_mask) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "NULL TCP spec/mask");
+				return -rte_errno;
+			}
+
+			/* Check TCP mask and update input set */
+			if (tcp_mask->hdr.sent_seq ||
+			    tcp_mask->hdr.recv_ack ||
+			    tcp_mask->hdr.data_off ||
+			    tcp_mask->hdr.tcp_flags ||
+			    tcp_mask->hdr.rx_win ||
+			    tcp_mask->hdr.cksum ||
+			    tcp_mask->hdr.tcp_urp) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid TCP mask");
+				return -rte_errno;
+			}
+
+			if (tcp_mask->hdr.src_port != UINT16_MAX ||
+			    tcp_mask->hdr.dst_port != UINT16_MAX) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid TCP mask");
+				return -rte_errno;
+			}
+
+			input_set |= I40E_INSET_SRC_PORT;
+			input_set |= I40E_INSET_DST_PORT;
+
+			/* Get filter info */
+			if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
+				flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_TCP;
+			else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
+				flow_type = RTE_ETH_FLOW_NONFRAG_IPV6_TCP;
+
+			if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
+				filter->input.flow.tcp4_flow.src_port =
+					tcp_spec->hdr.src_port;
+				filter->input.flow.tcp4_flow.dst_port =
+					tcp_spec->hdr.dst_port;
+			} else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
+				filter->input.flow.tcp6_flow.src_port =
+					tcp_spec->hdr.src_port;
+				filter->input.flow.tcp6_flow.dst_port =
+					tcp_spec->hdr.dst_port;
+			}
+			break;
+		case RTE_FLOW_ITEM_TYPE_UDP:
+			udp_spec = (const struct rte_flow_item_udp *)item->spec;
+			udp_mask = (const struct rte_flow_item_udp *)item->mask;
+			if (!udp_spec || !udp_mask) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "NULL UDP spec/mask");
+				return -rte_errno;
+			}
+
+			/* Check UDP mask and update input set*/
+			if (udp_mask->hdr.dgram_len ||
+			    udp_mask->hdr.dgram_cksum) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid UDP mask");
+				return -rte_errno;
+			}
+
+			if (udp_mask->hdr.src_port != UINT16_MAX ||
+			    udp_mask->hdr.dst_port != UINT16_MAX) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid UDP mask");
+				return -rte_errno;
+			}
+
+			input_set |= I40E_INSET_SRC_PORT;
+			input_set |= I40E_INSET_DST_PORT;
+
+			/* Get filter info */
+			if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
+				flow_type =
+					RTE_ETH_FLOW_NONFRAG_IPV4_UDP;
+			else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
+				flow_type =
+					RTE_ETH_FLOW_NONFRAG_IPV6_UDP;
+
+			if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
+				filter->input.flow.udp4_flow.src_port =
+					udp_spec->hdr.src_port;
+				filter->input.flow.udp4_flow.dst_port =
+					udp_spec->hdr.dst_port;
+			} else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
+				filter->input.flow.udp6_flow.src_port =
+					udp_spec->hdr.src_port;
+				filter->input.flow.udp6_flow.dst_port =
+					udp_spec->hdr.dst_port;
+			}
+			break;
+		case RTE_FLOW_ITEM_TYPE_SCTP:
+			sctp_spec =
+				(const struct rte_flow_item_sctp *)item->spec;
+			sctp_mask =
+				(const struct rte_flow_item_sctp *)item->mask;
+			if (!sctp_spec || !sctp_mask) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "NULL SCTP spec/mask");
+				return -rte_errno;
+			}
+
+			/* Check SCTP mask and update input set */
+			if (sctp_mask->hdr.cksum) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid UDP mask");
+				return -rte_errno;
+			}
+
+			if (sctp_mask->hdr.src_port != UINT16_MAX ||
+			    sctp_mask->hdr.dst_port != UINT16_MAX ||
+			    sctp_mask->hdr.tag != UINT32_MAX) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid UDP mask");
+				return -rte_errno;
+			}
+			input_set |= I40E_INSET_SRC_PORT;
+			input_set |= I40E_INSET_DST_PORT;
+			input_set |= I40E_INSET_SCTP_VT;
+
+			/* Get filter info */
+			if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
+				flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_SCTP;
+			else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
+				flow_type = RTE_ETH_FLOW_NONFRAG_IPV6_SCTP;
+
+			if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
+				filter->input.flow.sctp4_flow.src_port =
+					sctp_spec->hdr.src_port;
+				filter->input.flow.sctp4_flow.dst_port =
+					sctp_spec->hdr.dst_port;
+				filter->input.flow.sctp4_flow.verify_tag =
+					sctp_spec->hdr.tag;
+			} else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
+				filter->input.flow.sctp6_flow.src_port =
+					sctp_spec->hdr.src_port;
+				filter->input.flow.sctp6_flow.dst_port =
+					sctp_spec->hdr.dst_port;
+				filter->input.flow.sctp6_flow.verify_tag =
+					sctp_spec->hdr.tag;
+			}
+			break;
+		case RTE_FLOW_ITEM_TYPE_VF:
+			vf_spec = (const struct rte_flow_item_vf *)item->spec;
+			filter->input.flow_ext.is_vf = 1;
+			filter->input.flow_ext.dst_id = vf_spec->id;
+			if (filter->input.flow_ext.is_vf &&
+			    filter->input.flow_ext.dst_id >= pf->vf_num) {
+				rte_flow_error_set(error, EINVAL,
+						   RTE_FLOW_ERROR_TYPE_ITEM,
+						   item,
+						   "Invalid VF ID for FDIR.");
+				return -rte_errno;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	pctype = i40e_flowtype_to_pctype(flow_type);
+	if (pctype == 0 || pctype > I40E_FILTER_PCTYPE_L2_PAYLOAD) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, item,
+				   "Unsupported flow type");
+		return -rte_errno;
+	}
+
+	if (input_set != i40e_get_default_input_set(pctype)) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ITEM, item,
+				   "Invalid input set.");
+		return -rte_errno;
+	}
+	filter->input.flow_type = flow_type;
+
+	return 0;
+}
+
+/* Parse to get the action info of a FDIR filter.
+ * FDIR action supports QUEUE or (QUEUE + MARK).
+ */
+static int
+i40e_flow_parse_fdir_action(struct rte_eth_dev *dev,
+			    const struct rte_flow_action *actions,
+			    struct rte_flow_error *error,
+			    struct rte_eth_fdir_filter *filter)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	const struct rte_flow_action *act;
+	const struct rte_flow_action_queue *act_q;
+	const struct rte_flow_action_mark *mark_spec;
+	uint32_t index = 0;
+
+	/* Check if the first non-void action is QUEUE or DROP. */
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	if (act->type != RTE_FLOW_ACTION_TYPE_QUEUE &&
+	    act->type != RTE_FLOW_ACTION_TYPE_DROP) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				   act, "Invalid action.");
+		return -rte_errno;
+	}
+
+	act_q = (const struct rte_flow_action_queue *)act->conf;
+	filter->action.flex_off = 0;
+	if (act->type == RTE_FLOW_ACTION_TYPE_QUEUE)
+		filter->action.behavior = RTE_ETH_FDIR_ACCEPT;
+	else
+		filter->action.behavior = RTE_ETH_FDIR_REJECT;
+
+	filter->action.report_status = RTE_ETH_FDIR_REPORT_ID;
+	filter->action.rx_queue = act_q->index;
+
+	if (filter->action.rx_queue >= pf->dev_data->nb_rx_queues) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ACTION, act,
+				   "Invalid queue ID for FDIR.");
+		return -rte_errno;
+	}
+
+	/* Check if the next non-void item is MARK or END. */
+	index++;
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	if (act->type != RTE_FLOW_ACTION_TYPE_MARK &&
+	    act->type != RTE_FLOW_ACTION_TYPE_END) {
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				   act, "Invalid action.");
+		return -rte_errno;
+	}
+
+	if (act->type == RTE_FLOW_ACTION_TYPE_MARK) {
+		mark_spec = (const struct rte_flow_action_mark *)act->conf;
+		filter->soft_id = mark_spec->id;
+
+		/* Check if the next non-void item is END */
+		index++;
+		NEXT_ITEM_OF_ACTION(act, actions, index);
+		if (act->type != RTE_FLOW_ACTION_TYPE_END) {
+			rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ACTION,
+					   act, "Invalid action.");
+			return -rte_errno;
+		}
+	}
+
+	return 0;
+}
+
+static int
+i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev,
+			    const struct rte_flow_attr *attr,
+			    const struct rte_flow_item pattern[],
+			    const struct rte_flow_action actions[],
+			    struct rte_flow_error *error,
+			    union i40e_filter_t *filter)
+{
+	struct rte_eth_fdir_filter *fdir_filter =
+		&filter->fdir_filter;
+	int ret;
+
+	ret = i40e_flow_parse_fdir_pattern(dev, pattern, error, fdir_filter);
+	if (ret)
+		return ret;
+
+	ret = i40e_flow_parse_fdir_action(dev, actions, error, fdir_filter);
+	if (ret)
+		return ret;
+
+	ret = i40e_flow_parse_attr(attr, error);
+	if (ret)
+		return ret;
+
+	if (dev->data->dev_conf.fdir_conf.mode !=
+	    RTE_FDIR_MODE_PERFECT) {
+		rte_flow_error_set(error, ENOTSUP,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+				   NULL,
+				   "Check the mode in fdir_conf.");
+		return -rte_errno;
+	}
+
+	return 0;
+}
+
 static int
 i40e_flow_validate(struct rte_eth_dev *dev,
 		   const struct rte_flow_attr *attr,
-- 
2.5.5

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox