[v4,3/6] net/ice: add protocol extraction support for per Rx queue

Message ID 20190919062553.79257-4-leyi.rong@intel.com (mailing list archive)
State Superseded, archived
Delegated to: xiaolong ye
Headers
Series enable Rx flexible descriptor |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation fail Compilation issues

Commit Message

Leyi Rong Sept. 19, 2019, 6:25 a.m. UTC
  From: Haiyue Wang <haiyue.wang@intel.com>

The ice has the feature to extract protocol fields into flex descriptor
by programming per queue. Currently, the ice PMD will put the protocol
fields into rte_mbuf::udata64 with different type format. Application
can access the protocol fields quickly.

Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
 doc/guides/nics/ice.rst                | 101 +++++++++
 doc/guides/rel_notes/release_19_11.rst |   4 +
 drivers/net/ice/Makefile               |   3 +
 drivers/net/ice/ice_ethdev.c           | 301 +++++++++++++++++++++++++
 drivers/net/ice/ice_ethdev.h           |   4 +
 drivers/net/ice/ice_rxtx.c             |  61 +++++
 drivers/net/ice/ice_rxtx.h             |   2 +
 drivers/net/ice/ice_rxtx_vec_common.h  |   3 +
 drivers/net/ice/meson.build            |   2 +
 drivers/net/ice/rte_pmd_ice.h          | 152 +++++++++++++
 10 files changed, 633 insertions(+)
 create mode 100644 drivers/net/ice/rte_pmd_ice.h
  

Comments

Qiming Yang Sept. 23, 2019, 3:25 a.m. UTC | #1
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Leyi Rong
> Sent: Thursday, September 19, 2019 2:26 PM
> To: Wang, Haiyue <haiyue.wang@intel.com>; Lu, Wenzhuo
> <wenzhuo.lu@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Ye, Xiaolong
> <xiaolong.ye@intel.com>
> Cc: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v4 3/6] net/ice: add protocol extraction support
> for per Rx queue
> 
> From: Haiyue Wang <haiyue.wang@intel.com>
> 
> The ice has the feature to extract protocol fields into flex descriptor by
> programming per queue. Currently, the ice PMD will put the protocol fields
> into rte_mbuf::udata64 with different type format. Application can access
> the protocol fields quickly.
> 
> Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> ---
>  doc/guides/nics/ice.rst                | 101 +++++++++
>  doc/guides/rel_notes/release_19_11.rst |   4 +
>  drivers/net/ice/Makefile               |   3 +
>  drivers/net/ice/ice_ethdev.c           | 301 +++++++++++++++++++++++++
>  drivers/net/ice/ice_ethdev.h           |   4 +
>  drivers/net/ice/ice_rxtx.c             |  61 +++++
>  drivers/net/ice/ice_rxtx.h             |   2 +
>  drivers/net/ice/ice_rxtx_vec_common.h  |   3 +
>  drivers/net/ice/meson.build            |   2 +
>  drivers/net/ice/rte_pmd_ice.h          | 152 +++++++++++++
>  10 files changed, 633 insertions(+)
>  create mode 100644 drivers/net/ice/rte_pmd_ice.h
> 
> diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst index
> 03819d29f..8a6f60e71 100644
> --- a/doc/guides/nics/ice.rst
> +++ b/doc/guides/nics/ice.rst
> @@ -61,6 +61,107 @@ Runtime Config Options
>    NOTE: In Safe mode, only very limited features are available, features like
> RSS,
>    checksum, fdir, tunneling ... are all disabled.
> 
> +- ``Protocol extraction for per queue``
> +
> +  Configure the RX queues to do protocol extraction into
> + ``rte_mbuf::udata64``  for protocol handling acceleration, like checking the
> TCP SYN packets quickly.
> +
> +  The argument format is::
> +
> +      -w 18:00.0,proto_xtr=<queues:protocol>[<queues:protocol>...]
> +      -w 18:00.0,proto_xtr=<protocol>
> +
> +  Queues are grouped by ``(`` and ``)`` within the group. The ``-``
> + character  is used as a range separator and ``,`` is used as a single number
> separator.
> +  The grouping ``()`` can be omitted for single element group. If no
> + queues are  specified, PMD will use this protocol extraction type for all
> queues.
> +
> +  Protocol is : ``vlan, ipv4, ipv6, ipv6_flow, tcp``.
> +
> +  .. code-block:: console
> +
> +    testpmd -w 18:00.0,proto_xtr='[(1,2-3,8-9):tcp,10-13:vlan]'
> +
> +  This setting means queues 1, 2-3, 8-9 are TCP extraction, queues
> + 10-13 are  VLAN extraction, other queues run with no protocol extraction.
> +
> +  .. code-block:: console
> +
> +    testpmd -w 18:00.0,proto_xtr=vlan,proto_xtr='[(1,2-3,8-9):tcp,10-23:ipv6]'
> +
> +  This setting means queues 1, 2-3, 8-9 are TCP extraction, queues
> + 10-23 are
> +  IPv6 extraction, other queues use the default VLAN extraction.
> +
> +  The extraction will be copied into the lower 32 bit of
> ``rte_mbuf::udata64``.
> +
> +  .. table:: Protocol extraction : ``vlan``
> +
> +   +----------------------------+----------------------------+
> +   |           VLAN2            |           VLAN1            |
> +   +======+===+=================+======+===+=================+
> +   |  PCP | D |       VID       |  PCP | D |       VID       |
> +   +------+---+-----------------+------+---+-----------------+
> +
> +  VLAN1 - single or EVLAN (first for QinQ).
> +
> +  VLAN2 - C-VLAN (second for QinQ).
> +
> +  .. table:: Protocol extraction : ``ipv4``
> +
> +   +----------------------------+----------------------------+
> +   |           IPHDR2           |           IPHDR1           |
> +   +======+=======+=============+==============+=============+
> +   |  Ver |Hdr Len|    ToS      |      TTL     |  Protocol   |
> +   +------+-------+-------------+--------------+-------------+
> +
> +  IPHDR1 - IPv4 header word 4, "TTL" and "Protocol" fields.
> +
> +  IPHDR2 - IPv4 header word 0, "Ver", "Hdr Len" and "Type of Service" fields.
> +
> +  .. table:: Protocol extraction : ``ipv6``
> +
> +   +----------------------------+----------------------------+
> +   |           IPHDR2           |           IPHDR1           |
> +   +=====+=============+========+=============+==============+
> +   | Ver |Traffic class|  Flow  | Next Header |   Hop Limit  |
> +   +-----+-------------+--------+-------------+--------------+
> +
> +  IPHDR1 - IPv6 header word 3, "Next Header" and "Hop Limit" fields.
> +
> +  IPHDR2 - IPv6 header word 0, "Ver", "Traffic class" and high 4 bits
> + of  "Flow Label" fields.
> +
> +  .. table:: Protocol extraction : ``ipv6_flow``
> +
> +   +----------------------------+----------------------------+
> +   |           IPHDR2           |           IPHDR1           |
> +   +=====+=============+========+============================+
> +   | Ver |Traffic class|            Flow Label               |
> +   +-----+-------------+-------------------------------------+
> +
> +  IPHDR1 - IPv6 header word 1, 16 low bits of the "Flow Label" field.
> +
> +  IPHDR2 - IPv6 header word 0, "Ver", "Traffic class" and high 4 bits
> + of  "Flow Label" fields.
> +
> +  .. table:: Protocol extraction : ``tcp``
> +
> +   +----------------------------+----------------------------+
> +   |           TCPHDR2          |           TCPHDR1          |
> +   +============================+======+======+==============+
> +   |          Reserved          |Offset|  RSV |     Flags    |
> +   +----------------------------+------+------+--------------+
> +
> +  TCPHDR1 - TCP header word 6, "Data Offset" and "Flags" fields.
> +
> +  TCPHDR2 - Reserved
> +
> +  Use ``get_proto_xtr_flds(struct rte_mbuf *mb)`` to access the
> + protocol  extraction, do not use ``rte_mbuf::udata64`` directly.
> +
> +  The ``dump_proto_xtr_flds(struct rte_mbuf *mb)`` routine shows how to
> + access the protocol extraction result in ``struct rte_mbuf``.
> +
>  Driver compilation and testing
>  ------------------------------
> 
> diff --git a/doc/guides/rel_notes/release_19_11.rst
> b/doc/guides/rel_notes/release_19_11.rst
> index 8490d897c..382806229 100644
> --- a/doc/guides/rel_notes/release_19_11.rst
> +++ b/doc/guides/rel_notes/release_19_11.rst
> @@ -21,6 +21,10 @@ DPDK Release 19.11
> 
>        xdg-open build/doc/html/guides/rel_notes/release_19_11.html
> 
> +* **Updated the ICE driver.**
> +
> +  * Added support for handling Receive Flex Descriptor.
> +  * Added support for protocol extraction on per Rx queue.
> 
>  New Features
>  ------------
> diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile index
> ae53c2646..4a279f196 100644
> --- a/drivers/net/ice/Makefile
> +++ b/drivers/net/ice/Makefile
> @@ -82,4 +82,7 @@ ifeq ($(CC_AVX2_SUPPORT), 1)  endif
>  SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
> 
> +# install this header file
> +SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
> +
>  include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c index
> 44a14cb8a..7c74b6169 100644
> --- a/drivers/net/ice/ice_ethdev.c
> +++ b/drivers/net/ice/ice_ethdev.c
> @@ -19,9 +19,11 @@
> 
>  /* devargs */
>  #define ICE_SAFE_MODE_SUPPORT_ARG "safe-mode-support"
> +#define ICE_PROTO_XTR_ARG         "proto_xtr"
> 
>  static const char * const ice_valid_args[] = {
>  	ICE_SAFE_MODE_SUPPORT_ARG,
> +	ICE_PROTO_XTR_ARG,
>  	NULL
>  };
> 
> @@ -257,6 +259,280 @@ ice_init_controlq_parameter(struct ice_hw *hw)
>  	hw->mailboxq.sq_buf_size = ICE_MAILBOXQ_BUF_SZ;  }
> 
> +static int
> +lookup_proto_xtr_type(const char *xtr_name) {
> +	static struct {
> +		const char *name;
> +		enum proto_xtr_type type;
> +	} xtr_type_map[] = {
> +		{ "vlan",      PROTO_XTR_VLAN      },
> +		{ "ipv4",      PROTO_XTR_IPV4      },
> +		{ "ipv6",      PROTO_XTR_IPV6      },
> +		{ "ipv6_flow", PROTO_XTR_IPV6_FLOW },
> +		{ "tcp",       PROTO_XTR_TCP       },
> +	};
> +	uint32_t i;
> +
> +	for (i = 0; i < RTE_DIM(xtr_type_map); i++) {
> +		if (strcmp(xtr_name, xtr_type_map[i].name) == 0)
> +			return xtr_type_map[i].type;
> +	}
> +
> +	return -1;
> +}
> +
> +/*
> + * Parse elem, the elem could be single number/range or '(' ')' group
> + * 1) A single number elem, it's just a simple digit. e.g. 9
> + * 2) A single range elem, two digits with a '-' between. e.g. 2-6
> + * 3) A group elem, combines multiple 1) or 2) with '( )'. e.g (0,2-4,6)
> + *    Within group elem, '-' used for a range separator;
> + *                       ',' used for a single number.
> + */
> +static int
> +parse_queue_set(const char *input, int xtr_type, struct ice_devargs
> +*devargs) {
> +	const char *str = input;
> +	char *end = NULL;
> +	uint32_t min, max;
> +	uint32_t idx;
> +
> +	while (isblank(*str))
> +		str++;
> +
> +	if (!isdigit(*str) && *str != '(')
> +		return -1;
> +
> +	/* process single number or single range of number */
> +	if (*str != '(') {
> +		errno = 0;
> +		idx = strtoul(str, &end, 10);
> +		if (errno || end == NULL || idx >= ICE_MAX_QUEUE_NUM)
> +			return -1;
> +
> +		while (isblank(*end))
> +			end++;
> +
> +		min = idx;
> +		max = idx;
> +
> +		/* process single <number>-<number> */
> +		if (*end == '-') {
> +			end++;
> +			while (isblank(*end))
> +				end++;
> +			if (!isdigit(*end))
> +				return -1;
> +
> +			errno = 0;
> +			idx = strtoul(end, &end, 10);
> +			if (errno || end == NULL || idx >=
> ICE_MAX_QUEUE_NUM)
> +				return -1;
> +
> +			max = idx;
> +			while (isblank(*end))
> +				end++;
> +		}
> +
> +		if (*end != ':')
> +			return -1;
> +
> +		for (idx = RTE_MIN(min, max);
> +		     idx <= RTE_MAX(min, max); idx++)
> +			devargs->proto_xtr[idx] = xtr_type;
> +
> +		return 0;
> +	}
> +
> +	/* process set within bracket */
> +	str++;
> +	while (isblank(*str))
> +		str++;
> +	if (*str == '\0')
> +		return -1;
> +
> +	min = ICE_MAX_QUEUE_NUM;
> +	do {
> +		/* go ahead to the first digit */
> +		while (isblank(*str))
> +			str++;
> +		if (!isdigit(*str))
> +			return -1;
> +
> +		/* get the digit value */
> +		errno = 0;
> +		idx = strtoul(str, &end, 10);
> +		if (errno || end == NULL || idx >= ICE_MAX_QUEUE_NUM)
> +			return -1;
> +
> +		/* go ahead to separator '-',',' and ')' */
> +		while (isblank(*end))
> +			end++;
> +		if (*end == '-') {
> +			if (min == ICE_MAX_QUEUE_NUM)
> +				min = idx;
> +			else /* avoid continuous '-' */
> +				return -1;
> +		} else if (*end == ',' || *end == ')') {
> +			max = idx;
> +			if (min == ICE_MAX_QUEUE_NUM)
> +				min = idx;
> +
> +			for (idx = RTE_MIN(min, max);
> +			     idx <= RTE_MAX(min, max); idx++)
> +				devargs->proto_xtr[idx] = xtr_type;
> +
> +			min = ICE_MAX_QUEUE_NUM;
> +		} else {
> +			return -1;
> +		}
> +
> +		str = end + 1;
> +	} while (*end != ')' && *end != '\0');
> +
> +	return 0;
> +}
> +
> +static int
> +parse_queue_proto_xtr(const char *queues, struct ice_devargs *devargs)
> +{
> +	const char *queue_start;
> +	uint32_t idx;
> +	int xtr_type;
> +	char xtr_name[32];
> +
> +	while (isblank(*queues))
> +		queues++;
> +
> +	if (*queues != '[') {
> +		xtr_type = lookup_proto_xtr_type(queues);
> +		if (xtr_type < 0)
> +			return -1;
> +
> +		memset(devargs->proto_xtr, xtr_type,
> +		       sizeof(devargs->proto_xtr));
> +
> +		return 0;
> +	}
> +
> +	queues++;
> +	do {
> +		while (isblank(*queues))
> +			queues++;
> +		if (*queues == '\0')
> +			return -1;
> +
> +		queue_start = queues;
> +
> +		/* go across a complete bracket */
> +		if (*queue_start == '(') {
> +			queues += strcspn(queues, ")");
> +			if (*queues != ')')
> +				return -1;
> +		}
> +
> +		/* scan the separator ':' */
> +		queues += strcspn(queues, ":");
> +		if (*queues++ != ':')
> +			return -1;
> +		while (isblank(*queues))
> +			queues++;
> +
> +		for (idx = 0; ; idx++) {
> +			if (isblank(queues[idx]) ||
> +			    queues[idx] == ',' ||
> +			    queues[idx] == ']' ||
> +			    queues[idx] == '\0')
> +				break;
> +
> +			if (idx > sizeof(xtr_name) - 2)
> +				return -1;
> +
> +			xtr_name[idx] = queues[idx];
> +		}
> +		xtr_name[idx] = '\0';
> +		xtr_type = lookup_proto_xtr_type(xtr_name);
> +		if (xtr_type < 0)
> +			return -1;
> +
> +		queues += idx;
> +
> +		while (isblank(*queues) || *queues == ',' || *queues == ']')
> +			queues++;
> +
> +		if (parse_queue_set(queue_start, xtr_type, devargs) < 0)
> +			return -1;
> +	} while (*queues != '\0');
> +
> +	return 0;
> +}
> +
> +static int
> +handle_proto_xtr_arg(__rte_unused const char *key, const char *value,
> +		     void *extra_args)
> +{
> +	struct ice_devargs *devargs = extra_args;
> +
> +	if (value == NULL || extra_args == NULL)
> +		return -EINVAL;
> +
> +	if (parse_queue_proto_xtr(value, devargs) < 0) {
> +		PMD_DRV_LOG(ERR,
> +			    "The protocol extraction parameter is wrong : '%s'",
> +			    value);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static bool
> +ice_proto_xtr_support(struct ice_hw *hw) { #define FLX_REG(val, fld,
> +idx) \
> +	(((val) & GLFLXP_RXDID_FLX_WRD_##idx##_##fld##_M) >> \
> +	 GLFLXP_RXDID_FLX_WRD_##idx##_##fld##_S)
> +	static struct {
> +		uint32_t rxdid;
> +		uint16_t protid_0;
> +		uint16_t protid_1;
> +	} xtr_sets[] = {
> +		{ ICE_RXDID_COMMS_AUX_VLAN, ICE_PROT_EVLAN_O,
> ICE_PROT_VLAN_O },
> +		{ ICE_RXDID_COMMS_AUX_IPV4, ICE_PROT_IPV4_OF_OR_S,
> +		  ICE_PROT_IPV4_OF_OR_S },
> +		{ ICE_RXDID_COMMS_AUX_IPV6, ICE_PROT_IPV6_OF_OR_S,
> +		  ICE_PROT_IPV6_OF_OR_S },
> +		{ ICE_RXDID_COMMS_AUX_IPV6_FLOW,
> ICE_PROT_IPV6_OF_OR_S,
> +		  ICE_PROT_IPV6_OF_OR_S },
> +		{ ICE_RXDID_COMMS_AUX_TCP, ICE_PROT_TCP_IL,
> ICE_PROT_ID_INVAL },
> +	};
> +	uint32_t i;
> +
> +	for (i = 0; i < RTE_DIM(xtr_sets); i++) {
> +		uint32_t rxdid = xtr_sets[i].rxdid;
> +		uint32_t v;
> +
> +		if (xtr_sets[i].protid_0 != ICE_PROT_ID_INVAL) {
> +			v = ICE_READ_REG(hw,
> GLFLXP_RXDID_FLX_WRD_4(rxdid));
> +
> +			if (FLX_REG(v, PROT_MDID, 4) != xtr_sets[i].protid_0
> ||
> +			    FLX_REG(v, RXDID_OPCODE, 4) !=
> ICE_RX_OPC_EXTRACT)
> +				return false;
> +		}
> +
> +		if (xtr_sets[i].protid_1 != ICE_PROT_ID_INVAL) {
> +			v = ICE_READ_REG(hw,
> GLFLXP_RXDID_FLX_WRD_5(rxdid));
> +
> +			if (FLX_REG(v, PROT_MDID, 5) != xtr_sets[i].protid_1
> ||
> +			    FLX_REG(v, RXDID_OPCODE, 5) !=
> ICE_RX_OPC_EXTRACT)
> +				return false;
> +		}
> +	}
> +
> +	return true;
> +}
> +
>  static int
>  ice_res_pool_init(struct ice_res_pool_info *pool, uint32_t base,
>  		  uint32_t num)
> @@ -1079,6 +1355,8 @@ ice_interrupt_handler(void *param)  static int
> ice_pf_sw_init(struct rte_eth_dev *dev)  {
> +	struct ice_adapter *ad =
> +			ICE_DEV_PRIVATE_TO_ADAPTER(dev->data-
> >dev_private);
>  	struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
>  	struct ice_hw *hw = ICE_PF_TO_HW(pf);
> 
> @@ -1088,6 +1366,16 @@ ice_pf_sw_init(struct rte_eth_dev *dev)
> 
>  	pf->lan_nb_qps = pf->lan_nb_qp_max;
> 
> +	if (ice_proto_xtr_support(hw))
> +		pf->proto_xtr = rte_zmalloc(NULL, pf->lan_nb_qps, 0);
> +
> +	if (pf->proto_xtr != NULL)
> +		rte_memcpy(pf->proto_xtr, ad->devargs.proto_xtr,
> +			   RTE_MIN((size_t)pf->lan_nb_qps,
> +				   sizeof(ad->devargs.proto_xtr)));
> +	else
> +		PMD_DRV_LOG(NOTICE, "Protocol extraction is disabled");
> +
>  	return 0;
>  }
> 
> @@ -1378,9 +1666,18 @@ static int ice_parse_devargs(struct rte_eth_dev
> *dev)
>  		return -EINVAL;
>  	}
> 
> +	memset(ad->devargs.proto_xtr, PROTO_XTR_NONE,
> +	       sizeof(ad->devargs.proto_xtr));
> +
> +	ret = rte_kvargs_process(kvlist, ICE_PROTO_XTR_ARG,
> +				 &handle_proto_xtr_arg, &ad->devargs);
> +	if (ret)
> +		goto bail;
> +

Why is bail?

>  	ret = rte_kvargs_process(kvlist, ICE_SAFE_MODE_SUPPORT_ARG,
>  				 &parse_bool, &ad-
> >devargs.safe_mode_support);
> 
> +bail:
>  	rte_kvargs_free(kvlist);
>  	return ret;
>  }
> @@ -1547,6 +1844,7 @@ ice_dev_init(struct rte_eth_dev *dev)
>  	ice_sched_cleanup_all(hw);
>  	rte_free(hw->port_info);
>  	ice_shutdown_all_ctrlq(hw);
> +	rte_free(pf->proto_xtr);
> 
>  	return ret;
>  }
> @@ -1672,6 +1970,8 @@ ice_dev_close(struct rte_eth_dev *dev)
>  	rte_free(hw->port_info);
>  	hw->port_info = NULL;
>  	ice_shutdown_all_ctrlq(hw);
> +	rte_free(pf->proto_xtr);
> +	pf->proto_xtr = NULL;
>  }
> 
>  static int
> @@ -3795,6 +4095,7 @@ RTE_PMD_REGISTER_PCI(net_ice, rte_ice_pmd);
> RTE_PMD_REGISTER_PCI_TABLE(net_ice, pci_id_ice_map);
> RTE_PMD_REGISTER_KMOD_DEP(net_ice, "* igb_uio | uio_pci_generic | vfio-
> pci");  RTE_PMD_REGISTER_PARAM_STRING(net_ice,
> +			      ICE_PROTO_XTR_ARG
> "=[queue:]<vlan|ipv4|ipv6|ipv6_flow|tcp>"
>  			      ICE_SAFE_MODE_SUPPORT_ARG "=<0|1>");
> 
>  RTE_INIT(ice_init_log)
> diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h index
> f569da833..adbb66322 100644
> --- a/drivers/net/ice/ice_ethdev.h
> +++ b/drivers/net/ice/ice_ethdev.h
> @@ -263,6 +263,7 @@ struct ice_pf {
>  	uint16_t lan_nb_qp_max;
>  	uint16_t lan_nb_qps; /* The number of queue pairs of LAN */
>  	uint16_t base_queue; /* The base queue pairs index  in the device
> */
> +	uint8_t *proto_xtr; /* Protocol extraction type for all queues */
>  	struct ice_hw_port_stats stats_offset;
>  	struct ice_hw_port_stats stats;
>  	/* internal packet statistics, it should be excluded from the total */
> @@ -273,11 +274,14 @@ struct ice_pf {
>  	struct ice_flow_list flow_list;
>  };
> 
> +#define ICE_MAX_QUEUE_NUM  2048
> +
>  /**
>   * Cache devargs parse result.
>   */
>  struct ice_devargs {
>  	int safe_mode_support;
> +	uint8_t proto_xtr[ICE_MAX_QUEUE_NUM];
>  };
> 
>  /**
> diff --git a/drivers/net/ice/ice_rxtx.c b/drivers/net/ice/ice_rxtx.c index
> d2e36853f..e28310b96 100644
> --- a/drivers/net/ice/ice_rxtx.c
> +++ b/drivers/net/ice/ice_rxtx.c
> @@ -13,6 +13,36 @@
>  		PKT_TX_TCP_SEG |		 \
>  		PKT_TX_OUTER_IP_CKSUM)
> 
> +static inline uint8_t
> +ice_rxdid_to_proto_xtr_type(uint8_t rxdid) {
> +	static uint8_t xtr_map[] = {
> +		[ICE_RXDID_COMMS_AUX_VLAN]      = PROTO_XTR_VLAN,
> +		[ICE_RXDID_COMMS_AUX_IPV4]      = PROTO_XTR_IPV4,
> +		[ICE_RXDID_COMMS_AUX_IPV6]      = PROTO_XTR_IPV6,
> +		[ICE_RXDID_COMMS_AUX_IPV6_FLOW] =
> PROTO_XTR_IPV6_FLOW,
> +		[ICE_RXDID_COMMS_AUX_TCP]       = PROTO_XTR_TCP,
> +	};
> +
> +	return rxdid < RTE_DIM(xtr_map) ? xtr_map[rxdid] :
> PROTO_XTR_NONE; }
> +
> +static inline uint8_t
> +ice_proto_xtr_type_to_rxdid(uint8_t xtr_tpye) {
> +	static uint8_t rxdid_map[] = {
> +		[PROTO_XTR_VLAN]      = ICE_RXDID_COMMS_AUX_VLAN,
> +		[PROTO_XTR_IPV4]      = ICE_RXDID_COMMS_AUX_IPV4,
> +		[PROTO_XTR_IPV6]      = ICE_RXDID_COMMS_AUX_IPV6,
> +		[PROTO_XTR_IPV6_FLOW] =
> ICE_RXDID_COMMS_AUX_IPV6_FLOW,
> +		[PROTO_XTR_TCP]       = ICE_RXDID_COMMS_AUX_TCP,
> +	};
> +	uint8_t rxdid;
> +
> +	rxdid = xtr_tpye < RTE_DIM(rxdid_map) ? rxdid_map[xtr_tpye] : 0;
> +
> +	return rxdid != 0 ? rxdid : ICE_RXDID_COMMS_GENERIC; }
> 
>  static enum ice_status
>  ice_program_hw_rx_queue(struct ice_rx_queue *rxq) @@ -84,6 +114,11
> @@ ice_program_hw_rx_queue(struct ice_rx_queue *rxq)
>  	rx_ctx.showiv = 0;
>  	rx_ctx.crcstrip = (rxq->crc_len == 0) ? 1 : 0;
> 
> +	rxdid = ice_proto_xtr_type_to_rxdid(rxq->proto_xtr);
> +
> +	PMD_DRV_LOG(DEBUG, "Port (%u) - Rx queue (%u) is set with
> RXDID : %u",
> +		    rxq->port_id, rxq->queue_id, rxdid);
> +
>  	/* Enable Flexible Descriptors in the queue context which
>  	 * allows this driver to select a specific receive descriptor format
>  	 */
> @@ -641,6 +676,8 @@ ice_rx_queue_setup(struct rte_eth_dev *dev,
>  	rxq->drop_en = rx_conf->rx_drop_en;
>  	rxq->vsi = vsi;
>  	rxq->rx_deferred_start = rx_conf->rx_deferred_start;
> +	rxq->proto_xtr = pf->proto_xtr != NULL ?
> +			 pf->proto_xtr[queue_idx] : PROTO_XTR_NONE;
> 
>  	/* Allocate the maximun number of RX ring hardware descriptor. */
>  	len = ICE_MAX_RING_DESC;
> @@ -1062,6 +1099,10 @@ ice_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile
> union ice_rx_flex_desc *rxdp)
>  		   mb->vlan_tci, mb->vlan_tci_outer);  }
> 
> +#define ICE_RX_PROTO_XTR_VALID \
> +	((1 << ICE_RX_FLEX_DESC_STATUS1_XTRMD4_VALID_S) | \
> +	 (1 << ICE_RX_FLEX_DESC_STATUS1_XTRMD5_VALID_S))
> +
>  static inline void
>  ice_rxd_to_pkt_fields(struct rte_mbuf *mb,
>  		      volatile union ice_rx_flex_desc *rxdp) @@ -1075,6
> +1116,26 @@ ice_rxd_to_pkt_fields(struct rte_mbuf *mb,
>  		mb->ol_flags |= PKT_RX_RSS_HASH;
>  		mb->hash.rss = rte_le_to_cpu_32(desc->rss_hash);
>  	}
> +
> +#ifndef RTE_LIBRTE_ICE_16BYTE_RX_DESC
> +	init_proto_xtr_flds(mb);
> +
> +	stat_err = rte_le_to_cpu_16(desc->status_error1);
> +	if (stat_err & ICE_RX_PROTO_XTR_VALID) {
> +		struct proto_xtr_flds *xtr = get_proto_xtr_flds(mb);
> +
> +		if (stat_err & (1 <<
> ICE_RX_FLEX_DESC_STATUS1_XTRMD4_VALID_S))
> +			xtr->u.raw.data0 =
> +				rte_le_to_cpu_16(desc->flex_ts.flex.aux0);
> +
> +		if (stat_err & (1 <<
> ICE_RX_FLEX_DESC_STATUS1_XTRMD5_VALID_S))
> +			xtr->u.raw.data1 =
> +				rte_le_to_cpu_16(desc->flex_ts.flex.aux1);
> +
> +		xtr->type = ice_rxdid_to_proto_xtr_type(desc->rxdid);
> +		xtr->magic = PROTO_XTR_MAGIC_ID;
> +	}
> +#endif
>  }
> 
>  #ifdef RTE_LIBRTE_ICE_RX_ALLOW_BULK_ALLOC
> diff --git a/drivers/net/ice/ice_rxtx.h b/drivers/net/ice/ice_rxtx.h index
> 64e891875..de16637f3 100644
> --- a/drivers/net/ice/ice_rxtx.h
> +++ b/drivers/net/ice/ice_rxtx.h
> @@ -5,6 +5,7 @@
>  #ifndef _ICE_RXTX_H_
>  #define _ICE_RXTX_H_
> 
> +#include "rte_pmd_ice.h"
>  #include "ice_ethdev.h"
> 
>  #define ICE_ALIGN_RING_DESC  32
> @@ -78,6 +79,7 @@ struct ice_rx_queue {
>  	uint16_t max_pkt_len; /* Maximum packet length */
>  	bool q_set; /* indicate if rx queue has been configured */
>  	bool rx_deferred_start; /* don't start this queue in dev start */
> +	uint8_t proto_xtr; /* Protocol extraction from flexible descriptor */
>  	ice_rx_release_mbufs_t rx_rel_mbufs;
>  };
> 
> diff --git a/drivers/net/ice/ice_rxtx_vec_common.h
> b/drivers/net/ice/ice_rxtx_vec_common.h
> index c5f0d564f..080ca4175 100644
> --- a/drivers/net/ice/ice_rxtx_vec_common.h
> +++ b/drivers/net/ice/ice_rxtx_vec_common.h
> @@ -234,6 +234,9 @@ ice_rx_vec_queue_default(struct ice_rx_queue *rxq)
>  	if (rxq->nb_rx_desc % rxq->rx_free_thresh)
>  		return -1;
> 
> +	if (rxq->proto_xtr != PROTO_XTR_NONE)
> +		return -1;
> +
>  	return 0;
>  }
> 
> diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build index
> 36b4b3c85..6828170a9 100644
> --- a/drivers/net/ice/meson.build
> +++ b/drivers/net/ice/meson.build
> @@ -34,3 +34,5 @@ if arch_subdir == 'x86'
>  		objs += ice_avx2_lib.extract_objects('ice_rxtx_vec_avx2.c')
>  	endif
>  endif
> +
> +install_headers('rte_pmd_ice.h')
> diff --git a/drivers/net/ice/rte_pmd_ice.h b/drivers/net/ice/rte_pmd_ice.h
> new file mode 100644 index 000000000..719487e1e
> --- /dev/null
> +++ b/drivers/net/ice/rte_pmd_ice.h
> @@ -0,0 +1,152 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2019 Intel Corporation
> + */
> +
> +#ifndef _RTE_PMD_ICE_H_
> +#define _RTE_PMD_ICE_H_
> +
> +#include <stdio.h>
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +enum proto_xtr_type {
> +	PROTO_XTR_NONE,
> +	PROTO_XTR_VLAN,
> +	PROTO_XTR_IPV4,
> +	PROTO_XTR_IPV6,
> +	PROTO_XTR_IPV6_FLOW,
> +	PROTO_XTR_TCP,
> +};
> +
> +struct proto_xtr_flds {
> +	union {
> +		struct {
> +			uint16_t data0;
> +			uint16_t data1;
> +		} raw;
> +		struct {
> +			uint16_t stag_vid:12,
> +				 stag_dei:1,
> +				 stag_pcp:3;
> +			uint16_t ctag_vid:12,
> +				 ctag_dei:1,
> +				 ctag_pcp:3;
> +		} vlan;
> +		struct {
> +			uint16_t protocol:8,
> +				 ttl:8;
> +			uint16_t tos:8,
> +				 ihl:4,
> +				 version:4;
> +		} ipv4;
> +		struct {
> +			uint16_t hoplimit:8,
> +				 nexthdr:8;
> +			uint16_t flowhi4:4,
> +				 tc:8,
> +				 version:4;
> +		} ipv6;
> +		struct {
> +			uint16_t flowlo16;
> +			uint16_t flowhi4:4,
> +				 tc:8,
> +				 version:4;
> +		} ipv6_flow;
> +		struct {
> +			uint16_t fin:1,
> +				 syn:1,
> +				 rst:1,
> +				 psh:1,
> +				 ack:1,
> +				 urg:1,
> +				 ece:1,
> +				 cwr:1,
> +				 res1:4,
> +				 doff:4;
> +			uint16_t rsvd;
> +		} tcp;
> +	} u;
> +
> +	uint16_t rsvd;
> +
> +	uint8_t type;
> +
> +#define PROTO_XTR_MAGIC_ID	0xCE
> +	uint8_t magic;
> +};
> +
> +static inline void
> +init_proto_xtr_flds(struct rte_mbuf *mb) {
> +	mb->udata64 = 0;
> +}
> +
> +static inline struct proto_xtr_flds *
> +get_proto_xtr_flds(struct rte_mbuf *mb) {
> +	RTE_BUILD_BUG_ON(sizeof(struct proto_xtr_flds) > sizeof(mb-
> >udata64));
> +
> +	return (struct proto_xtr_flds *)&mb->udata64; }
> +
> +static inline void
> +dump_proto_xtr_flds(struct rte_mbuf *mb) {
> +	struct proto_xtr_flds *xtr = get_proto_xtr_flds(mb);
> +
> +	if (xtr->magic != PROTO_XTR_MAGIC_ID || xtr->type ==
> PROTO_XTR_NONE)
> +		return;
> +
> +	printf(" - Protocol Extraction:[0x%04x:0x%04x],",
> +	       xtr->u.raw.data0, xtr->u.raw.data1);
> +
> +	if (xtr->type == PROTO_XTR_VLAN)
> +		printf("vlan,stag=%u:%u:%u,ctag=%u:%u:%u ",
> +		       xtr->u.vlan.stag_pcp,
> +		       xtr->u.vlan.stag_dei,
> +		       xtr->u.vlan.stag_vid,
> +		       xtr->u.vlan.ctag_pcp,
> +		       xtr->u.vlan.ctag_dei,
> +		       xtr->u.vlan.ctag_vid);
> +	else if (xtr->type == PROTO_XTR_IPV4)
> +		printf("ipv4,ver=%u,hdrlen=%u,tos=%u,ttl=%u,proto=%u ",
> +		       xtr->u.ipv4.version,
> +		       xtr->u.ipv4.ihl,
> +		       xtr->u.ipv4.tos,
> +		       xtr->u.ipv4.ttl,
> +		       xtr->u.ipv4.protocol);
> +	else if (xtr->type == PROTO_XTR_IPV6)
> +
> 	printf("ipv6,ver=%u,tc=%u,flow_hi4=0x%x,nexthdr=%u,hoplimit=%u ",
> +		       xtr->u.ipv6.version,
> +		       xtr->u.ipv6.tc,
> +		       xtr->u.ipv6.flowhi4,
> +		       xtr->u.ipv6.nexthdr,
> +		       xtr->u.ipv6.hoplimit);
> +	else if (xtr->type == PROTO_XTR_IPV6_FLOW)
> +		printf("ipv6_flow,ver=%u,tc=%u,flow=0x%x%04x ",
> +		       xtr->u.ipv6_flow.version,
> +		       xtr->u.ipv6_flow.tc,
> +		       xtr->u.ipv6_flow.flowhi4,
> +		       xtr->u.ipv6_flow.flowlo16);
> +	else if (xtr->type == PROTO_XTR_TCP)
> +		printf("tcp,doff=%u,flags=%s%s%s%s%s%s%s%s ",
> +		       xtr->u.tcp.doff,
> +		       xtr->u.tcp.cwr ? "C" : "",
> +		       xtr->u.tcp.ece ? "E" : "",
> +		       xtr->u.tcp.urg ? "U" : "",
> +		       xtr->u.tcp.ack ? "A" : "",
> +		       xtr->u.tcp.psh ? "P" : "",
> +		       xtr->u.tcp.rst ? "R" : "",
> +		       xtr->u.tcp.syn ? "S" : "",
> +		       xtr->u.tcp.fin ? "F" : "");
> +}
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* _RTE_PMD_ICE_H_ */
> --
> 2.17.1
  
Wang, Haiyue Sept. 23, 2019, 3:34 a.m. UTC | #2
> -----Original Message-----
> From: Yang, Qiming
> Sent: Monday, September 23, 2019 11:26
> To: Rong, Leyi <leyi.rong@intel.com>; Wang, Haiyue <haiyue.wang@intel.com>; Lu, Wenzhuo
> <wenzhuo.lu@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Ye, Xiaolong <xiaolong.ye@intel.com>
> Cc: dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 3/6] net/ice: add protocol extraction support for per Rx queue
> 
> 
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Leyi Rong
> > Sent: Thursday, September 19, 2019 2:26 PM
> > To: Wang, Haiyue <haiyue.wang@intel.com>; Lu, Wenzhuo
> > <wenzhuo.lu@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Ye, Xiaolong
> > <xiaolong.ye@intel.com>
> > Cc: dev@dpdk.org
> > Subject: [dpdk-dev] [PATCH v4 3/6] net/ice: add protocol extraction support
> > for per Rx queue
> >
> > From: Haiyue Wang <haiyue.wang@intel.com>
> >
> > The ice has the feature to extract protocol fields into flex descriptor by
> > programming per queue. Currently, the ice PMD will put the protocol fields
> > into rte_mbuf::udata64 with different type format. Application can access
> > the protocol fields quickly.
> >
> > Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> > ---
> >  doc/guides/nics/ice.rst                | 101 +++++++++
> >  doc/guides/rel_notes/release_19_11.rst |   4 +
> >  drivers/net/ice/Makefile               |   3 +
> >  drivers/net/ice/ice_ethdev.c           | 301 +++++++++++++++++++++++++
> >  drivers/net/ice/ice_ethdev.h           |   4 +
> >  drivers/net/ice/ice_rxtx.c             |  61 +++++
> >  drivers/net/ice/ice_rxtx.h             |   2 +
> >  drivers/net/ice/ice_rxtx_vec_common.h  |   3 +
> >  drivers/net/ice/meson.build            |   2 +
> >  drivers/net/ice/rte_pmd_ice.h          | 152 +++++++++++++
> >  10 files changed, 633 insertions(+)
> >  create mode 100644 drivers/net/ice/rte_pmd_ice.h
> >
> > diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst index
> > 03819d29f..8a6f60e71 100644
> > --- a/doc/guides/nics/ice.rst
> > +++ b/doc/guides/nics/ice.rst
> > @@ -61,6 +61,107 @@ Runtime Config Options
> >    NOTE: In Safe mode, only very limited features are available, features like
> > RSS,
> >    checksum, fdir, tunneling ... are all disabled.
> >
> > +- ``Protocol extraction for per queue``
> > +
> > +  Configure the RX queues to do protocol extraction into
> > + ``rte_mbuf::udata64``  for protocol handling acceleration, like checking the
> > TCP SYN packets quickly.
> > +
> > +  The argument format is::
> > +
> > +      -w 18:00.0,proto_xtr=<queues:protocol>[<queues:protocol>...]
> > +      -w 18:00.0,proto_xtr=<protocol>
> > +
> > +  Queues are grouped by ``(`` and ``)`` within the group. The ``-``
> > + character  is used as a range separator and ``,`` is used as a single number
> > separator.
> > +  The grouping ``()`` can be omitted for single element group. If no
> > + queues are  specified, PMD will use this protocol extraction type for all
> > queues.
> > +
> > +  Protocol is : ``vlan, ipv4, ipv6, ipv6_flow, tcp``.
> > +
> > +  .. code-block:: console
> > +
> > +    testpmd -w 18:00.0,proto_xtr='[(1,2-3,8-9):tcp,10-13:vlan]'
> > +
> > +  This setting means queues 1, 2-3, 8-9 are TCP extraction, queues
> > + 10-13 are  VLAN extraction, other queues run with no protocol extraction.
> > +
> > +  .. code-block:: console
> > +
> > +    testpmd -w 18:00.0,proto_xtr=vlan,proto_xtr='[(1,2-3,8-9):tcp,10-23:ipv6]'
> > +
> > +  This setting means queues 1, 2-3, 8-9 are TCP extraction, queues
> > + 10-23 are
> > +  IPv6 extraction, other queues use the default VLAN extraction.
> > +
> > +  The extraction will be copied into the lower 32 bit of
> > ``rte_mbuf::udata64``.
> > +
> > +  .. table:: Protocol extraction : ``vlan``
> > +
> > +   +----------------------------+----------------------------+
> > +   |           VLAN2            |           VLAN1            |
> > +   +======+===+=================+======+===+=================+
> > +   |  PCP | D |       VID       |  PCP | D |       VID       |
> > +   +------+---+-----------------+------+---+-----------------+
> > +
> > +  VLAN1 - single or EVLAN (first for QinQ).
> > +
> > +  VLAN2 - C-VLAN (second for QinQ).
> > +
> > +  .. table:: Protocol extraction : ``ipv4``
> > +
> > +   +----------------------------+----------------------------+
> > +   |           IPHDR2           |           IPHDR1           |
> > +   +======+=======+=============+==============+=============+
> > +   |  Ver |Hdr Len|    ToS      |      TTL     |  Protocol   |
> > +   +------+-------+-------------+--------------+-------------+
> > +
> > +  IPHDR1 - IPv4 header word 4, "TTL" and "Protocol" fields.
> > +
> > +  IPHDR2 - IPv4 header word 0, "Ver", "Hdr Len" and "Type of Service" fields.
> > +
> > +  .. table:: Protocol extraction : ``ipv6``
> > +
> > +   +----------------------------+----------------------------+
> > +   |           IPHDR2           |           IPHDR1           |
> > +   +=====+=============+========+=============+==============+
> > +   | Ver |Traffic class|  Flow  | Next Header |   Hop Limit  |
> > +   +-----+-------------+--------+-------------+--------------+
> > +
> > +  IPHDR1 - IPv6 header word 3, "Next Header" and "Hop Limit" fields.
> > +
> > +  IPHDR2 - IPv6 header word 0, "Ver", "Traffic class" and high 4 bits
> > + of  "Flow Label" fields.
> > +
> > +  .. table:: Protocol extraction : ``ipv6_flow``
> > +
> > +   +----------------------------+----------------------------+
> > +   |           IPHDR2           |           IPHDR1           |
> > +   +=====+=============+========+============================+
> > +   | Ver |Traffic class|            Flow Label               |
> > +   +-----+-------------+-------------------------------------+
> > +
> > +  IPHDR1 - IPv6 header word 1, 16 low bits of the "Flow Label" field.
> > +
> > +  IPHDR2 - IPv6 header word 0, "Ver", "Traffic class" and high 4 bits
> > + of  "Flow Label" fields.
> > +
> > +  .. table:: Protocol extraction : ``tcp``
> > +
> > +   +----------------------------+----------------------------+
> > +   |           TCPHDR2          |           TCPHDR1          |
> > +   +============================+======+======+==============+
> > +   |          Reserved          |Offset|  RSV |     Flags    |
> > +   +----------------------------+------+------+--------------+
> > +
> > +  TCPHDR1 - TCP header word 6, "Data Offset" and "Flags" fields.
> > +
> > +  TCPHDR2 - Reserved
> > +
> > +  Use ``get_proto_xtr_flds(struct rte_mbuf *mb)`` to access the
> > + protocol  extraction, do not use ``rte_mbuf::udata64`` directly.
> > +
> > +  The ``dump_proto_xtr_flds(struct rte_mbuf *mb)`` routine shows how to
> > + access the protocol extraction result in ``struct rte_mbuf``.
> > +
> >  Driver compilation and testing
> >  ------------------------------
> >
> > diff --git a/doc/guides/rel_notes/release_19_11.rst
> > b/doc/guides/rel_notes/release_19_11.rst
> > index 8490d897c..382806229 100644
> > --- a/doc/guides/rel_notes/release_19_11.rst
> > +++ b/doc/guides/rel_notes/release_19_11.rst
> > @@ -21,6 +21,10 @@ DPDK Release 19.11
> >
> >        xdg-open build/doc/html/guides/rel_notes/release_19_11.html
> >
> > +* **Updated the ICE driver.**
> > +
> > +  * Added support for handling Receive Flex Descriptor.
> > +  * Added support for protocol extraction on per Rx queue.
> >
> >  New Features
> >  ------------
> > diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile index
> > ae53c2646..4a279f196 100644
> > --- a/drivers/net/ice/Makefile
> > +++ b/drivers/net/ice/Makefile
> > @@ -82,4 +82,7 @@ ifeq ($(CC_AVX2_SUPPORT), 1)  endif
> >  SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
> >
> > +# install this header file
> > +SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
> > +
> >  include $(RTE_SDK)/mk/rte.lib.mk
> > diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c index
> > 44a14cb8a..7c74b6169 100644
> > --- a/drivers/net/ice/ice_ethdev.c
> > +++ b/drivers/net/ice/ice_ethdev.c
> > @@ -19,9 +19,11 @@
> >
> >  /* devargs */
> >  #define ICE_SAFE_MODE_SUPPORT_ARG "safe-mode-support"
> > +#define ICE_PROTO_XTR_ARG         "proto_xtr"
> >
> >  static const char * const ice_valid_args[] = {
> >  	ICE_SAFE_MODE_SUPPORT_ARG,
> > +	ICE_PROTO_XTR_ARG,
> >  	NULL
> >  };
> >
> > @@ -257,6 +259,280 @@ ice_init_controlq_parameter(struct ice_hw *hw)
> >  	hw->mailboxq.sq_buf_size = ICE_MAILBOXQ_BUF_SZ;  }
> >
> > +static int
> > +lookup_proto_xtr_type(const char *xtr_name) {
> > +	static struct {
> > +		const char *name;
> > +		enum proto_xtr_type type;
> > +	} xtr_type_map[] = {
> > +		{ "vlan",      PROTO_XTR_VLAN      },
> > +		{ "ipv4",      PROTO_XTR_IPV4      },
> > +		{ "ipv6",      PROTO_XTR_IPV6      },
> > +		{ "ipv6_flow", PROTO_XTR_IPV6_FLOW },
> > +		{ "tcp",       PROTO_XTR_TCP       },
> > +	};
> > +	uint32_t i;
> > +
> > +	for (i = 0; i < RTE_DIM(xtr_type_map); i++) {
> > +		if (strcmp(xtr_name, xtr_type_map[i].name) == 0)
> > +			return xtr_type_map[i].type;
> > +	}
> > +
> > +	return -1;
> > +}
> > +
> > +/*
> > + * Parse elem, the elem could be single number/range or '(' ')' group
> > + * 1) A single number elem, it's just a simple digit. e.g. 9
> > + * 2) A single range elem, two digits with a '-' between. e.g. 2-6
> > + * 3) A group elem, combines multiple 1) or 2) with '( )'. e.g (0,2-4,6)
> > + *    Within group elem, '-' used for a range separator;
> > + *                       ',' used for a single number.
> > + */
> > +static int
> > +parse_queue_set(const char *input, int xtr_type, struct ice_devargs
> > +*devargs) {
> > +	const char *str = input;
> > +	char *end = NULL;
> > +	uint32_t min, max;
> > +	uint32_t idx;
> > +
> > +	while (isblank(*str))
> > +		str++;
> > +
> > +	if (!isdigit(*str) && *str != '(')
> > +		return -1;
> > +
> > +	/* process single number or single range of number */
> > +	if (*str != '(') {
> > +		errno = 0;
> > +		idx = strtoul(str, &end, 10);
> > +		if (errno || end == NULL || idx >= ICE_MAX_QUEUE_NUM)
> > +			return -1;
> > +
> > +		while (isblank(*end))
> > +			end++;
> > +
> > +		min = idx;
> > +		max = idx;
> > +
> > +		/* process single <number>-<number> */
> > +		if (*end == '-') {
> > +			end++;
> > +			while (isblank(*end))
> > +				end++;
> > +			if (!isdigit(*end))
> > +				return -1;
> > +
> > +			errno = 0;
> > +			idx = strtoul(end, &end, 10);
> > +			if (errno || end == NULL || idx >=
> > ICE_MAX_QUEUE_NUM)
> > +				return -1;
> > +
> > +			max = idx;
> > +			while (isblank(*end))
> > +				end++;
> > +		}
> > +
> > +		if (*end != ':')
> > +			return -1;
> > +
> > +		for (idx = RTE_MIN(min, max);
> > +		     idx <= RTE_MAX(min, max); idx++)
> > +			devargs->proto_xtr[idx] = xtr_type;
> > +
> > +		return 0;
> > +	}
> > +
> > +	/* process set within bracket */
> > +	str++;
> > +	while (isblank(*str))
> > +		str++;
> > +	if (*str == '\0')
> > +		return -1;
> > +
> > +	min = ICE_MAX_QUEUE_NUM;
> > +	do {
> > +		/* go ahead to the first digit */
> > +		while (isblank(*str))
> > +			str++;
> > +		if (!isdigit(*str))
> > +			return -1;
> > +
> > +		/* get the digit value */
> > +		errno = 0;
> > +		idx = strtoul(str, &end, 10);
> > +		if (errno || end == NULL || idx >= ICE_MAX_QUEUE_NUM)
> > +			return -1;
> > +
> > +		/* go ahead to separator '-',',' and ')' */
> > +		while (isblank(*end))
> > +			end++;
> > +		if (*end == '-') {
> > +			if (min == ICE_MAX_QUEUE_NUM)
> > +				min = idx;
> > +			else /* avoid continuous '-' */
> > +				return -1;
> > +		} else if (*end == ',' || *end == ')') {
> > +			max = idx;
> > +			if (min == ICE_MAX_QUEUE_NUM)
> > +				min = idx;
> > +
> > +			for (idx = RTE_MIN(min, max);
> > +			     idx <= RTE_MAX(min, max); idx++)
> > +				devargs->proto_xtr[idx] = xtr_type;
> > +
> > +			min = ICE_MAX_QUEUE_NUM;
> > +		} else {
> > +			return -1;
> > +		}
> > +
> > +		str = end + 1;
> > +	} while (*end != ')' && *end != '\0');
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +parse_queue_proto_xtr(const char *queues, struct ice_devargs *devargs)
> > +{
> > +	const char *queue_start;
> > +	uint32_t idx;
> > +	int xtr_type;
> > +	char xtr_name[32];
> > +
> > +	while (isblank(*queues))
> > +		queues++;
> > +
> > +	if (*queues != '[') {
> > +		xtr_type = lookup_proto_xtr_type(queues);
> > +		if (xtr_type < 0)
> > +			return -1;
> > +
> > +		memset(devargs->proto_xtr, xtr_type,
> > +		       sizeof(devargs->proto_xtr));
> > +
> > +		return 0;
> > +	}
> > +
> > +	queues++;
> > +	do {
> > +		while (isblank(*queues))
> > +			queues++;
> > +		if (*queues == '\0')
> > +			return -1;
> > +
> > +		queue_start = queues;
> > +
> > +		/* go across a complete bracket */
> > +		if (*queue_start == '(') {
> > +			queues += strcspn(queues, ")");
> > +			if (*queues != ')')
> > +				return -1;
> > +		}
> > +
> > +		/* scan the separator ':' */
> > +		queues += strcspn(queues, ":");
> > +		if (*queues++ != ':')
> > +			return -1;
> > +		while (isblank(*queues))
> > +			queues++;
> > +
> > +		for (idx = 0; ; idx++) {
> > +			if (isblank(queues[idx]) ||
> > +			    queues[idx] == ',' ||
> > +			    queues[idx] == ']' ||
> > +			    queues[idx] == '\0')
> > +				break;
> > +
> > +			if (idx > sizeof(xtr_name) - 2)
> > +				return -1;
> > +
> > +			xtr_name[idx] = queues[idx];
> > +		}
> > +		xtr_name[idx] = '\0';
> > +		xtr_type = lookup_proto_xtr_type(xtr_name);
> > +		if (xtr_type < 0)
> > +			return -1;
> > +
> > +		queues += idx;
> > +
> > +		while (isblank(*queues) || *queues == ',' || *queues == ']')
> > +			queues++;
> > +
> > +		if (parse_queue_set(queue_start, xtr_type, devargs) < 0)
> > +			return -1;
> > +	} while (*queues != '\0');
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +handle_proto_xtr_arg(__rte_unused const char *key, const char *value,
> > +		     void *extra_args)
> > +{
> > +	struct ice_devargs *devargs = extra_args;
> > +
> > +	if (value == NULL || extra_args == NULL)
> > +		return -EINVAL;
> > +
> > +	if (parse_queue_proto_xtr(value, devargs) < 0) {
> > +		PMD_DRV_LOG(ERR,
> > +			    "The protocol extraction parameter is wrong : '%s'",
> > +			    value);
> > +		return -1;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static bool
> > +ice_proto_xtr_support(struct ice_hw *hw) { #define FLX_REG(val, fld,
> > +idx) \
> > +	(((val) & GLFLXP_RXDID_FLX_WRD_##idx##_##fld##_M) >> \
> > +	 GLFLXP_RXDID_FLX_WRD_##idx##_##fld##_S)
> > +	static struct {
> > +		uint32_t rxdid;
> > +		uint16_t protid_0;
> > +		uint16_t protid_1;
> > +	} xtr_sets[] = {
> > +		{ ICE_RXDID_COMMS_AUX_VLAN, ICE_PROT_EVLAN_O,
> > ICE_PROT_VLAN_O },
> > +		{ ICE_RXDID_COMMS_AUX_IPV4, ICE_PROT_IPV4_OF_OR_S,
> > +		  ICE_PROT_IPV4_OF_OR_S },
> > +		{ ICE_RXDID_COMMS_AUX_IPV6, ICE_PROT_IPV6_OF_OR_S,
> > +		  ICE_PROT_IPV6_OF_OR_S },
> > +		{ ICE_RXDID_COMMS_AUX_IPV6_FLOW,
> > ICE_PROT_IPV6_OF_OR_S,
> > +		  ICE_PROT_IPV6_OF_OR_S },
> > +		{ ICE_RXDID_COMMS_AUX_TCP, ICE_PROT_TCP_IL,
> > ICE_PROT_ID_INVAL },
> > +	};
> > +	uint32_t i;
> > +
> > +	for (i = 0; i < RTE_DIM(xtr_sets); i++) {
> > +		uint32_t rxdid = xtr_sets[i].rxdid;
> > +		uint32_t v;
> > +
> > +		if (xtr_sets[i].protid_0 != ICE_PROT_ID_INVAL) {
> > +			v = ICE_READ_REG(hw,
> > GLFLXP_RXDID_FLX_WRD_4(rxdid));
> > +
> > +			if (FLX_REG(v, PROT_MDID, 4) != xtr_sets[i].protid_0
> > ||
> > +			    FLX_REG(v, RXDID_OPCODE, 4) !=
> > ICE_RX_OPC_EXTRACT)
> > +				return false;
> > +		}
> > +
> > +		if (xtr_sets[i].protid_1 != ICE_PROT_ID_INVAL) {
> > +			v = ICE_READ_REG(hw,
> > GLFLXP_RXDID_FLX_WRD_5(rxdid));
> > +
> > +			if (FLX_REG(v, PROT_MDID, 5) != xtr_sets[i].protid_1
> > ||
> > +			    FLX_REG(v, RXDID_OPCODE, 5) !=
> > ICE_RX_OPC_EXTRACT)
> > +				return false;
> > +		}
> > +	}
> > +
> > +	return true;
> > +}
> > +
> >  static int
> >  ice_res_pool_init(struct ice_res_pool_info *pool, uint32_t base,
> >  		  uint32_t num)
> > @@ -1079,6 +1355,8 @@ ice_interrupt_handler(void *param)  static int
> > ice_pf_sw_init(struct rte_eth_dev *dev)  {
> > +	struct ice_adapter *ad =
> > +			ICE_DEV_PRIVATE_TO_ADAPTER(dev->data-
> > >dev_private);
> >  	struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
> >  	struct ice_hw *hw = ICE_PF_TO_HW(pf);
> >
> > @@ -1088,6 +1366,16 @@ ice_pf_sw_init(struct rte_eth_dev *dev)
> >
> >  	pf->lan_nb_qps = pf->lan_nb_qp_max;
> >
> > +	if (ice_proto_xtr_support(hw))
> > +		pf->proto_xtr = rte_zmalloc(NULL, pf->lan_nb_qps, 0);
> > +
> > +	if (pf->proto_xtr != NULL)
> > +		rte_memcpy(pf->proto_xtr, ad->devargs.proto_xtr,
> > +			   RTE_MIN((size_t)pf->lan_nb_qps,
> > +				   sizeof(ad->devargs.proto_xtr)));
> > +	else
> > +		PMD_DRV_LOG(NOTICE, "Protocol extraction is disabled");
> > +
> >  	return 0;
> >  }
> >
> > @@ -1378,9 +1666,18 @@ static int ice_parse_devargs(struct rte_eth_dev
> > *dev)
> >  		return -EINVAL;
> >  	}
> >
> > +	memset(ad->devargs.proto_xtr, PROTO_XTR_NONE,
> > +	       sizeof(ad->devargs.proto_xtr));
> > +
> > +	ret = rte_kvargs_process(kvlist, ICE_PROTO_XTR_ARG,
> > +				 &handle_proto_xtr_arg, &ad->devargs);
> > +	if (ret)
> > +		goto bail;
> > +
> 
> Why is bail?
> 

free & ret, since 'ret' is used, 'bail' name from kernel. :)

> >  	ret = rte_kvargs_process(kvlist, ICE_SAFE_MODE_SUPPORT_ARG,
> >  				 &parse_bool, &ad-
> > >devargs.safe_mode_support);
> >
> > +bail:
> >  	rte_kvargs_free(kvlist);
> >  	return ret;
> >  }
> > @@ -1547,6 +1844,7 @@ ice_dev_init(struct rte_eth_dev *dev)
> >  	ice_sched_cleanup_all(hw);
> >  	rte_free(hw->port_info);
> >  	ice_shutdown_all_ctrlq(hw);
> > +	rte_free(pf->proto_xtr);
> >
> >  	return ret;
> >  }
> > @@ -1672,6 +1970,8 @@ ice_dev_close(struct rte_eth_dev *dev)
> >  	rte_free(hw->port_info);
> >  	hw->port_info = NULL;
> >  	ice_shutdown_all_ctrlq(hw);
> > +	rte_free(pf->proto_xtr);
> > +	pf->proto_xtr = NULL;
> >  }
> >
> >  static int
> > @@ -3795,6 +4095,7 @@ RTE_PMD_REGISTER_PCI(net_ice, rte_ice_pmd);
> > RTE_PMD_REGISTER_PCI_TABLE(net_ice, pci_id_ice_map);
> > RTE_PMD_REGISTER_KMOD_DEP(net_ice, "* igb_uio | uio_pci_generic | vfio-
> > pci");  RTE_PMD_REGISTER_PARAM_STRING(net_ice,
> > +			      ICE_PROTO_XTR_ARG
> > "=[queue:]<vlan|ipv4|ipv6|ipv6_flow|tcp>"
> >  			      ICE_SAFE_MODE_SUPPORT_ARG "=<0|1>");
> >
> >  RTE_INIT(ice_init_log)
> > diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h index
> > f569da833..adbb66322 100644
> > --- a/drivers/net/ice/ice_ethdev.h
> > +++ b/drivers/net/ice/ice_ethdev.h
> > @@ -263,6 +263,7 @@ struct ice_pf {
> >  	uint16_t lan_nb_qp_max;
> >  	uint16_t lan_nb_qps; /* The number of queue pairs of LAN */
> >  	uint16_t base_queue; /* The base queue pairs index  in the device
> > */
> > +	uint8_t *proto_xtr; /* Protocol extraction type for all queues */
> >  	struct ice_hw_port_stats stats_offset;
> >  	struct ice_hw_port_stats stats;
> >  	/* internal packet statistics, it should be excluded from the total */
> > @@ -273,11 +274,14 @@ struct ice_pf {
> >  	struct ice_flow_list flow_list;
> >  };
> >
> > +#define ICE_MAX_QUEUE_NUM  2048
> > +
> >  /**
> >   * Cache devargs parse result.
> >   */
> >  struct ice_devargs {
> >  	int safe_mode_support;
> > +	uint8_t proto_xtr[ICE_MAX_QUEUE_NUM];
> >  };
> >
> >  /**
> > diff --git a/drivers/net/ice/ice_rxtx.c b/drivers/net/ice/ice_rxtx.c index
> > d2e36853f..e28310b96 100644
> > --- a/drivers/net/ice/ice_rxtx.c
> > +++ b/drivers/net/ice/ice_rxtx.c
> > @@ -13,6 +13,36 @@
> >  		PKT_TX_TCP_SEG |		 \
> >  		PKT_TX_OUTER_IP_CKSUM)
> >
> > +static inline uint8_t
> > +ice_rxdid_to_proto_xtr_type(uint8_t rxdid) {
> > +	static uint8_t xtr_map[] = {
> > +		[ICE_RXDID_COMMS_AUX_VLAN]      = PROTO_XTR_VLAN,
> > +		[ICE_RXDID_COMMS_AUX_IPV4]      = PROTO_XTR_IPV4,
> > +		[ICE_RXDID_COMMS_AUX_IPV6]      = PROTO_XTR_IPV6,
> > +		[ICE_RXDID_COMMS_AUX_IPV6_FLOW] =
> > PROTO_XTR_IPV6_FLOW,
> > +		[ICE_RXDID_COMMS_AUX_TCP]       = PROTO_XTR_TCP,
> > +	};
> > +
> > +	return rxdid < RTE_DIM(xtr_map) ? xtr_map[rxdid] :
> > PROTO_XTR_NONE; }
> > +
> > +static inline uint8_t
> > +ice_proto_xtr_type_to_rxdid(uint8_t xtr_tpye) {
> > +	static uint8_t rxdid_map[] = {
> > +		[PROTO_XTR_VLAN]      = ICE_RXDID_COMMS_AUX_VLAN,
> > +		[PROTO_XTR_IPV4]      = ICE_RXDID_COMMS_AUX_IPV4,
> > +		[PROTO_XTR_IPV6]      = ICE_RXDID_COMMS_AUX_IPV6,
> > +		[PROTO_XTR_IPV6_FLOW] =
> > ICE_RXDID_COMMS_AUX_IPV6_FLOW,
> > +		[PROTO_XTR_TCP]       = ICE_RXDID_COMMS_AUX_TCP,
> > +	};
> > +	uint8_t rxdid;
> > +
> > +	rxdid = xtr_tpye < RTE_DIM(rxdid_map) ? rxdid_map[xtr_tpye] : 0;
> > +
> > +	return rxdid != 0 ? rxdid : ICE_RXDID_COMMS_GENERIC; }
> >
> >  static enum ice_status
> >  ice_program_hw_rx_queue(struct ice_rx_queue *rxq) @@ -84,6 +114,11
> > @@ ice_program_hw_rx_queue(struct ice_rx_queue *rxq)
> >  	rx_ctx.showiv = 0;
> >  	rx_ctx.crcstrip = (rxq->crc_len == 0) ? 1 : 0;
> >
> > +	rxdid = ice_proto_xtr_type_to_rxdid(rxq->proto_xtr);
> > +
> > +	PMD_DRV_LOG(DEBUG, "Port (%u) - Rx queue (%u) is set with
> > RXDID : %u",
> > +		    rxq->port_id, rxq->queue_id, rxdid);
> > +
> >  	/* Enable Flexible Descriptors in the queue context which
> >  	 * allows this driver to select a specific receive descriptor format
> >  	 */
> > @@ -641,6 +676,8 @@ ice_rx_queue_setup(struct rte_eth_dev *dev,
> >  	rxq->drop_en = rx_conf->rx_drop_en;
> >  	rxq->vsi = vsi;
> >  	rxq->rx_deferred_start = rx_conf->rx_deferred_start;
> > +	rxq->proto_xtr = pf->proto_xtr != NULL ?
> > +			 pf->proto_xtr[queue_idx] : PROTO_XTR_NONE;
> >
> >  	/* Allocate the maximun number of RX ring hardware descriptor. */
> >  	len = ICE_MAX_RING_DESC;
> > @@ -1062,6 +1099,10 @@ ice_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile
> > union ice_rx_flex_desc *rxdp)
> >  		   mb->vlan_tci, mb->vlan_tci_outer);  }
> >
> > +#define ICE_RX_PROTO_XTR_VALID \
> > +	((1 << ICE_RX_FLEX_DESC_STATUS1_XTRMD4_VALID_S) | \
> > +	 (1 << ICE_RX_FLEX_DESC_STATUS1_XTRMD5_VALID_S))
> > +
> >  static inline void
> >  ice_rxd_to_pkt_fields(struct rte_mbuf *mb,
> >  		      volatile union ice_rx_flex_desc *rxdp) @@ -1075,6
> > +1116,26 @@ ice_rxd_to_pkt_fields(struct rte_mbuf *mb,
> >  		mb->ol_flags |= PKT_RX_RSS_HASH;
> >  		mb->hash.rss = rte_le_to_cpu_32(desc->rss_hash);
> >  	}
> > +
> > +#ifndef RTE_LIBRTE_ICE_16BYTE_RX_DESC
> > +	init_proto_xtr_flds(mb);
> > +
> > +	stat_err = rte_le_to_cpu_16(desc->status_error1);
> > +	if (stat_err & ICE_RX_PROTO_XTR_VALID) {
> > +		struct proto_xtr_flds *xtr = get_proto_xtr_flds(mb);
> > +
> > +		if (stat_err & (1 <<
> > ICE_RX_FLEX_DESC_STATUS1_XTRMD4_VALID_S))
> > +			xtr->u.raw.data0 =
> > +				rte_le_to_cpu_16(desc->flex_ts.flex.aux0);
> > +
> > +		if (stat_err & (1 <<
> > ICE_RX_FLEX_DESC_STATUS1_XTRMD5_VALID_S))
> > +			xtr->u.raw.data1 =
> > +				rte_le_to_cpu_16(desc->flex_ts.flex.aux1);
> > +
> > +		xtr->type = ice_rxdid_to_proto_xtr_type(desc->rxdid);
> > +		xtr->magic = PROTO_XTR_MAGIC_ID;
> > +	}
> > +#endif
> >  }
> >
> >  #ifdef RTE_LIBRTE_ICE_RX_ALLOW_BULK_ALLOC
> > diff --git a/drivers/net/ice/ice_rxtx.h b/drivers/net/ice/ice_rxtx.h index
> > 64e891875..de16637f3 100644
> > --- a/drivers/net/ice/ice_rxtx.h
> > +++ b/drivers/net/ice/ice_rxtx.h
> > @@ -5,6 +5,7 @@
> >  #ifndef _ICE_RXTX_H_
> >  #define _ICE_RXTX_H_
> >
> > +#include "rte_pmd_ice.h"
> >  #include "ice_ethdev.h"
> >
> >  #define ICE_ALIGN_RING_DESC  32
> > @@ -78,6 +79,7 @@ struct ice_rx_queue {
> >  	uint16_t max_pkt_len; /* Maximum packet length */
> >  	bool q_set; /* indicate if rx queue has been configured */
> >  	bool rx_deferred_start; /* don't start this queue in dev start */
> > +	uint8_t proto_xtr; /* Protocol extraction from flexible descriptor */
> >  	ice_rx_release_mbufs_t rx_rel_mbufs;
> >  };
> >
> > diff --git a/drivers/net/ice/ice_rxtx_vec_common.h
> > b/drivers/net/ice/ice_rxtx_vec_common.h
> > index c5f0d564f..080ca4175 100644
> > --- a/drivers/net/ice/ice_rxtx_vec_common.h
> > +++ b/drivers/net/ice/ice_rxtx_vec_common.h
> > @@ -234,6 +234,9 @@ ice_rx_vec_queue_default(struct ice_rx_queue *rxq)
> >  	if (rxq->nb_rx_desc % rxq->rx_free_thresh)
> >  		return -1;
> >
> > +	if (rxq->proto_xtr != PROTO_XTR_NONE)
> > +		return -1;
> > +
> >  	return 0;
> >  }
> >
> > diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build index
> > 36b4b3c85..6828170a9 100644
> > --- a/drivers/net/ice/meson.build
> > +++ b/drivers/net/ice/meson.build
> > @@ -34,3 +34,5 @@ if arch_subdir == 'x86'
> >  		objs += ice_avx2_lib.extract_objects('ice_rxtx_vec_avx2.c')
> >  	endif
> >  endif
> > +
> > +install_headers('rte_pmd_ice.h')
> > diff --git a/drivers/net/ice/rte_pmd_ice.h b/drivers/net/ice/rte_pmd_ice.h
> > new file mode 100644 index 000000000..719487e1e
> > --- /dev/null
> > +++ b/drivers/net/ice/rte_pmd_ice.h
> > @@ -0,0 +1,152 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(c) 2019 Intel Corporation
> > + */
> > +
> > +#ifndef _RTE_PMD_ICE_H_
> > +#define _RTE_PMD_ICE_H_
> > +
> > +#include <stdio.h>
> > +#include <rte_mbuf.h>
> > +#include <rte_ethdev.h>
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +enum proto_xtr_type {
> > +	PROTO_XTR_NONE,
> > +	PROTO_XTR_VLAN,
> > +	PROTO_XTR_IPV4,
> > +	PROTO_XTR_IPV6,
> > +	PROTO_XTR_IPV6_FLOW,
> > +	PROTO_XTR_TCP,
> > +};
> > +
> > +struct proto_xtr_flds {
> > +	union {
> > +		struct {
> > +			uint16_t data0;
> > +			uint16_t data1;
> > +		} raw;
> > +		struct {
> > +			uint16_t stag_vid:12,
> > +				 stag_dei:1,
> > +				 stag_pcp:3;
> > +			uint16_t ctag_vid:12,
> > +				 ctag_dei:1,
> > +				 ctag_pcp:3;
> > +		} vlan;
> > +		struct {
> > +			uint16_t protocol:8,
> > +				 ttl:8;
> > +			uint16_t tos:8,
> > +				 ihl:4,
> > +				 version:4;
> > +		} ipv4;
> > +		struct {
> > +			uint16_t hoplimit:8,
> > +				 nexthdr:8;
> > +			uint16_t flowhi4:4,
> > +				 tc:8,
> > +				 version:4;
> > +		} ipv6;
> > +		struct {
> > +			uint16_t flowlo16;
> > +			uint16_t flowhi4:4,
> > +				 tc:8,
> > +				 version:4;
> > +		} ipv6_flow;
> > +		struct {
> > +			uint16_t fin:1,
> > +				 syn:1,
> > +				 rst:1,
> > +				 psh:1,
> > +				 ack:1,
> > +				 urg:1,
> > +				 ece:1,
> > +				 cwr:1,
> > +				 res1:4,
> > +				 doff:4;
> > +			uint16_t rsvd;
> > +		} tcp;
> > +	} u;
> > +
> > +	uint16_t rsvd;
> > +
> > +	uint8_t type;
> > +
> > +#define PROTO_XTR_MAGIC_ID	0xCE
> > +	uint8_t magic;
> > +};
> > +
> > +static inline void
> > +init_proto_xtr_flds(struct rte_mbuf *mb) {
> > +	mb->udata64 = 0;
> > +}
> > +
> > +static inline struct proto_xtr_flds *
> > +get_proto_xtr_flds(struct rte_mbuf *mb) {
> > +	RTE_BUILD_BUG_ON(sizeof(struct proto_xtr_flds) > sizeof(mb-
> > >udata64));
> > +
> > +	return (struct proto_xtr_flds *)&mb->udata64; }
> > +
> > +static inline void
> > +dump_proto_xtr_flds(struct rte_mbuf *mb) {
> > +	struct proto_xtr_flds *xtr = get_proto_xtr_flds(mb);
> > +
> > +	if (xtr->magic != PROTO_XTR_MAGIC_ID || xtr->type ==
> > PROTO_XTR_NONE)
> > +		return;
> > +
> > +	printf(" - Protocol Extraction:[0x%04x:0x%04x],",
> > +	       xtr->u.raw.data0, xtr->u.raw.data1);
> > +
> > +	if (xtr->type == PROTO_XTR_VLAN)
> > +		printf("vlan,stag=%u:%u:%u,ctag=%u:%u:%u ",
> > +		       xtr->u.vlan.stag_pcp,
> > +		       xtr->u.vlan.stag_dei,
> > +		       xtr->u.vlan.stag_vid,
> > +		       xtr->u.vlan.ctag_pcp,
> > +		       xtr->u.vlan.ctag_dei,
> > +		       xtr->u.vlan.ctag_vid);
> > +	else if (xtr->type == PROTO_XTR_IPV4)
> > +		printf("ipv4,ver=%u,hdrlen=%u,tos=%u,ttl=%u,proto=%u ",
> > +		       xtr->u.ipv4.version,
> > +		       xtr->u.ipv4.ihl,
> > +		       xtr->u.ipv4.tos,
> > +		       xtr->u.ipv4.ttl,
> > +		       xtr->u.ipv4.protocol);
> > +	else if (xtr->type == PROTO_XTR_IPV6)
> > +
> > 	printf("ipv6,ver=%u,tc=%u,flow_hi4=0x%x,nexthdr=%u,hoplimit=%u ",
> > +		       xtr->u.ipv6.version,
> > +		       xtr->u.ipv6.tc,
> > +		       xtr->u.ipv6.flowhi4,
> > +		       xtr->u.ipv6.nexthdr,
> > +		       xtr->u.ipv6.hoplimit);
> > +	else if (xtr->type == PROTO_XTR_IPV6_FLOW)
> > +		printf("ipv6_flow,ver=%u,tc=%u,flow=0x%x%04x ",
> > +		       xtr->u.ipv6_flow.version,
> > +		       xtr->u.ipv6_flow.tc,
> > +		       xtr->u.ipv6_flow.flowhi4,
> > +		       xtr->u.ipv6_flow.flowlo16);
> > +	else if (xtr->type == PROTO_XTR_TCP)
> > +		printf("tcp,doff=%u,flags=%s%s%s%s%s%s%s%s ",
> > +		       xtr->u.tcp.doff,
> > +		       xtr->u.tcp.cwr ? "C" : "",
> > +		       xtr->u.tcp.ece ? "E" : "",
> > +		       xtr->u.tcp.urg ? "U" : "",
> > +		       xtr->u.tcp.ack ? "A" : "",
> > +		       xtr->u.tcp.psh ? "P" : "",
> > +		       xtr->u.tcp.rst ? "R" : "",
> > +		       xtr->u.tcp.syn ? "S" : "",
> > +		       xtr->u.tcp.fin ? "F" : "");
> > +}
> > +
> > +#ifdef __cplusplus
> > +}
> > +#endif
> > +
> > +#endif /* _RTE_PMD_ICE_H_ */
> > --
> > 2.17.1
  
Xiaolong Ye Sept. 23, 2019, 8:29 a.m. UTC | #3
On 09/23, Yang, Qiming wrote:
>
>

[snip]

>> @@ -1378,9 +1666,18 @@ static int ice_parse_devargs(struct rte_eth_dev
>> *dev)
>>  		return -EINVAL;
>>  	}
>> 
>> +	memset(ad->devargs.proto_xtr, PROTO_XTR_NONE,
>> +	       sizeof(ad->devargs.proto_xtr));
>> +
>> +	ret = rte_kvargs_process(kvlist, ICE_PROTO_XTR_ARG,
>> +				 &handle_proto_xtr_arg, &ad->devargs);
>> +	if (ret)
>> +		goto bail;
>> +
>
>Why is bail?
>

Minor nit, better to snip unrelated context for one single comment, otherwise
it's quite difficult to find it. :)

Thanks,
Xiaolong
  
Wang, Haiyue Sept. 23, 2019, 11:03 a.m. UTC | #4
> -----Original Message-----
> From: Ye, Xiaolong
> Sent: Monday, September 23, 2019 16:30
> To: Yang, Qiming <qiming.yang@intel.com>
> Cc: Rong, Leyi <leyi.rong@intel.com>; Wang, Haiyue <haiyue.wang@intel.com>; Lu, Wenzhuo
> <wenzhuo.lu@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v4 3/6] net/ice: add protocol extraction support for per Rx queue
> 
> On 09/23, Yang, Qiming wrote:
> >
> >
> 
> [snip]
> 
> >> @@ -1378,9 +1666,18 @@ static int ice_parse_devargs(struct rte_eth_dev
> >> *dev)
> >>  		return -EINVAL;
> >>  	}
> >>
> >> +	memset(ad->devargs.proto_xtr, PROTO_XTR_NONE,
> >> +	       sizeof(ad->devargs.proto_xtr));
> >> +
> >> +	ret = rte_kvargs_process(kvlist, ICE_PROTO_XTR_ARG,
> >> +				 &handle_proto_xtr_arg, &ad->devargs);
> >> +	if (ret)
> >> +		goto bail;
> >> +
> >
> >Why is bail?
> >
> 
> Minor nit, better to snip unrelated context for one single comment, otherwise
> it's quite difficult to find it. :)
> 

+1, I checked many lines very carefully to avoid miss something. :)

> Thanks,
> Xiaolong
  
Xiaolong Ye Sept. 23, 2019, 2:24 p.m. UTC | #5
On 09/19, Leyi Rong wrote:
>From: Haiyue Wang <haiyue.wang@intel.com>
> 

[snip]

>+static inline uint8_t
>+ice_rxdid_to_proto_xtr_type(uint8_t rxdid)
>+{
>+	static uint8_t xtr_map[] = {
>+		[ICE_RXDID_COMMS_AUX_VLAN]      = PROTO_XTR_VLAN,
>+		[ICE_RXDID_COMMS_AUX_IPV4]      = PROTO_XTR_IPV4,
>+		[ICE_RXDID_COMMS_AUX_IPV6]      = PROTO_XTR_IPV6,
>+		[ICE_RXDID_COMMS_AUX_IPV6_FLOW] = PROTO_XTR_IPV6_FLOW,
>+		[ICE_RXDID_COMMS_AUX_TCP]       = PROTO_XTR_TCP,
>+	};
>+
>+	return rxdid < RTE_DIM(xtr_map) ? xtr_map[rxdid] : PROTO_XTR_NONE;
>+}
>+
>+static inline uint8_t
>+ice_proto_xtr_type_to_rxdid(uint8_t xtr_tpye)

s/xtr_tpye/xtr_type/

>+{
>+	static uint8_t rxdid_map[] = {
>+		[PROTO_XTR_VLAN]      = ICE_RXDID_COMMS_AUX_VLAN,
>+		[PROTO_XTR_IPV4]      = ICE_RXDID_COMMS_AUX_IPV4,
>+		[PROTO_XTR_IPV6]      = ICE_RXDID_COMMS_AUX_IPV6,
>+		[PROTO_XTR_IPV6_FLOW] = ICE_RXDID_COMMS_AUX_IPV6_FLOW,
>+		[PROTO_XTR_TCP]       = ICE_RXDID_COMMS_AUX_TCP,
>+	};
>+	uint8_t rxdid;
>+
>+	rxdid = xtr_tpye < RTE_DIM(rxdid_map) ? rxdid_map[xtr_tpye] : 0;
>+
>+	return rxdid != 0 ? rxdid : ICE_RXDID_COMMS_GENERIC;

Maybe just 

	return xtr_type < RTE_DIM(rxdid_map) ?
				rxdid_map[xtr_type] : ICE_RXDID_COMMS_GENERIC;

as previous ice_rxdid_to_proto_xtr_type.


Thanks,
Xiaolong
  
Wang, Haiyue Sept. 23, 2019, 3 p.m. UTC | #6
> -----Original Message-----
> From: Ye, Xiaolong
> Sent: Monday, September 23, 2019 22:24
> To: Rong, Leyi <leyi.rong@intel.com>
> Cc: Wang, Haiyue <haiyue.wang@intel.com>; Lu, Wenzhuo <wenzhuo.lu@intel.com>; Zhang, Qi Z
> <qi.z.zhang@intel.com>; dev@dpdk.org
> Subject: Re: [PATCH v4 3/6] net/ice: add protocol extraction support for per Rx queue
> 
> On 09/19, Leyi Rong wrote:
> >From: Haiyue Wang <haiyue.wang@intel.com>
> >
> 
> [snip]
> 
> >+static inline uint8_t
> >+ice_rxdid_to_proto_xtr_type(uint8_t rxdid)
> >+{
> >+	static uint8_t xtr_map[] = {
> >+		[ICE_RXDID_COMMS_AUX_VLAN]      = PROTO_XTR_VLAN,
> >+		[ICE_RXDID_COMMS_AUX_IPV4]      = PROTO_XTR_IPV4,
> >+		[ICE_RXDID_COMMS_AUX_IPV6]      = PROTO_XTR_IPV6,
> >+		[ICE_RXDID_COMMS_AUX_IPV6_FLOW] = PROTO_XTR_IPV6_FLOW,
> >+		[ICE_RXDID_COMMS_AUX_TCP]       = PROTO_XTR_TCP,
> >+	};
> >+
> >+	return rxdid < RTE_DIM(xtr_map) ? xtr_map[rxdid] : PROTO_XTR_NONE;
> >+}
> >+
> >+static inline uint8_t
> >+ice_proto_xtr_type_to_rxdid(uint8_t xtr_tpye)
> 
> s/xtr_tpye/xtr_type/
> 

Got it!

> >+{
> >+	static uint8_t rxdid_map[] = {
Add this line:
		[PROTO_XTR_NONE]      = ICE_RXDID_COMMS_GENERIC,
> >+		[PROTO_XTR_VLAN]      = ICE_RXDID_COMMS_AUX_VLAN,
> >+		[PROTO_XTR_IPV4]      = ICE_RXDID_COMMS_AUX_IPV4,
> >+		[PROTO_XTR_IPV6]      = ICE_RXDID_COMMS_AUX_IPV6,
> >+		[PROTO_XTR_IPV6_FLOW] = ICE_RXDID_COMMS_AUX_IPV6_FLOW,
> >+		[PROTO_XTR_TCP]       = ICE_RXDID_COMMS_AUX_TCP,
> >+	};
> >+	uint8_t rxdid;
> >+
> >+	rxdid = xtr_tpye < RTE_DIM(rxdid_map) ? rxdid_map[xtr_tpye] : 0;
> >+
> >+	return rxdid != 0 ? rxdid : ICE_RXDID_COMMS_GENERIC;
> 
> Maybe just
> 
> 	return xtr_type < RTE_DIM(rxdid_map) ?
> 				rxdid_map[xtr_type] : ICE_RXDID_COMMS_GENERIC;
> 

Then this, will be updated in next version.

> as previous ice_rxdid_to_proto_xtr_type.
> 
> 
> Thanks,
> Xiaolong
  
Xiaolong Ye Sept. 23, 2019, 3:55 p.m. UTC | #7
On 09/23, Wang, Haiyue wrote:

>> >+{
>> >+	static uint8_t rxdid_map[] = {
>Add this line:
>		[PROTO_XTR_NONE]      = ICE_RXDID_COMMS_GENERIC,

This makes sense.

>> >+		[PROTO_XTR_VLAN]      = ICE_RXDID_COMMS_AUX_VLAN,
>> >+		[PROTO_XTR_IPV4]      = ICE_RXDID_COMMS_AUX_IPV4,
>> >+		[PROTO_XTR_IPV6]      = ICE_RXDID_COMMS_AUX_IPV6,
>> >+		[PROTO_XTR_IPV6_FLOW] = ICE_RXDID_COMMS_AUX_IPV6_FLOW,
>> >+		[PROTO_XTR_TCP]       = ICE_RXDID_COMMS_AUX_TCP,
>> >+	};
>> >+	uint8_t rxdid;
>> >+
>> >+	rxdid = xtr_tpye < RTE_DIM(rxdid_map) ? rxdid_map[xtr_tpye] : 0;
>> >+
>> >+	return rxdid != 0 ? rxdid : ICE_RXDID_COMMS_GENERIC;
>> 
>> Maybe just
>> 
>> 	return xtr_type < RTE_DIM(rxdid_map) ?
>> 				rxdid_map[xtr_type] : ICE_RXDID_COMMS_GENERIC;
>> 
>
>Then this, will be updated in next version.
>
>> as previous ice_rxdid_to_proto_xtr_type.
>> 
>> 
>> Thanks,
>> Xiaolong
  

Patch

diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 03819d29f..8a6f60e71 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -61,6 +61,107 @@  Runtime Config Options
   NOTE: In Safe mode, only very limited features are available, features like RSS,
   checksum, fdir, tunneling ... are all disabled.
 
+- ``Protocol extraction for per queue``
+
+  Configure the RX queues to do protocol extraction into ``rte_mbuf::udata64``
+  for protocol handling acceleration, like checking the TCP SYN packets quickly.
+
+  The argument format is::
+
+      -w 18:00.0,proto_xtr=<queues:protocol>[<queues:protocol>...]
+      -w 18:00.0,proto_xtr=<protocol>
+
+  Queues are grouped by ``(`` and ``)`` within the group. The ``-`` character
+  is used as a range separator and ``,`` is used as a single number separator.
+  The grouping ``()`` can be omitted for single element group. If no queues are
+  specified, PMD will use this protocol extraction type for all queues.
+
+  Protocol is : ``vlan, ipv4, ipv6, ipv6_flow, tcp``.
+
+  .. code-block:: console
+
+    testpmd -w 18:00.0,proto_xtr='[(1,2-3,8-9):tcp,10-13:vlan]'
+
+  This setting means queues 1, 2-3, 8-9 are TCP extraction, queues 10-13 are
+  VLAN extraction, other queues run with no protocol extraction.
+
+  .. code-block:: console
+
+    testpmd -w 18:00.0,proto_xtr=vlan,proto_xtr='[(1,2-3,8-9):tcp,10-23:ipv6]'
+
+  This setting means queues 1, 2-3, 8-9 are TCP extraction, queues 10-23 are
+  IPv6 extraction, other queues use the default VLAN extraction.
+
+  The extraction will be copied into the lower 32 bit of ``rte_mbuf::udata64``.
+
+  .. table:: Protocol extraction : ``vlan``
+
+   +----------------------------+----------------------------+
+   |           VLAN2            |           VLAN1            |
+   +======+===+=================+======+===+=================+
+   |  PCP | D |       VID       |  PCP | D |       VID       |
+   +------+---+-----------------+------+---+-----------------+
+
+  VLAN1 - single or EVLAN (first for QinQ).
+
+  VLAN2 - C-VLAN (second for QinQ).
+
+  .. table:: Protocol extraction : ``ipv4``
+
+   +----------------------------+----------------------------+
+   |           IPHDR2           |           IPHDR1           |
+   +======+=======+=============+==============+=============+
+   |  Ver |Hdr Len|    ToS      |      TTL     |  Protocol   |
+   +------+-------+-------------+--------------+-------------+
+
+  IPHDR1 - IPv4 header word 4, "TTL" and "Protocol" fields.
+
+  IPHDR2 - IPv4 header word 0, "Ver", "Hdr Len" and "Type of Service" fields.
+
+  .. table:: Protocol extraction : ``ipv6``
+
+   +----------------------------+----------------------------+
+   |           IPHDR2           |           IPHDR1           |
+   +=====+=============+========+=============+==============+
+   | Ver |Traffic class|  Flow  | Next Header |   Hop Limit  |
+   +-----+-------------+--------+-------------+--------------+
+
+  IPHDR1 - IPv6 header word 3, "Next Header" and "Hop Limit" fields.
+
+  IPHDR2 - IPv6 header word 0, "Ver", "Traffic class" and high 4 bits of
+  "Flow Label" fields.
+
+  .. table:: Protocol extraction : ``ipv6_flow``
+
+   +----------------------------+----------------------------+
+   |           IPHDR2           |           IPHDR1           |
+   +=====+=============+========+============================+
+   | Ver |Traffic class|            Flow Label               |
+   +-----+-------------+-------------------------------------+
+
+  IPHDR1 - IPv6 header word 1, 16 low bits of the "Flow Label" field.
+
+  IPHDR2 - IPv6 header word 0, "Ver", "Traffic class" and high 4 bits of
+  "Flow Label" fields.
+
+  .. table:: Protocol extraction : ``tcp``
+
+   +----------------------------+----------------------------+
+   |           TCPHDR2          |           TCPHDR1          |
+   +============================+======+======+==============+
+   |          Reserved          |Offset|  RSV |     Flags    |
+   +----------------------------+------+------+--------------+
+
+  TCPHDR1 - TCP header word 6, "Data Offset" and "Flags" fields.
+
+  TCPHDR2 - Reserved
+
+  Use ``get_proto_xtr_flds(struct rte_mbuf *mb)`` to access the protocol
+  extraction, do not use ``rte_mbuf::udata64`` directly.
+
+  The ``dump_proto_xtr_flds(struct rte_mbuf *mb)`` routine shows how to
+  access the protocol extraction result in ``struct rte_mbuf``.
+
 Driver compilation and testing
 ------------------------------
 
diff --git a/doc/guides/rel_notes/release_19_11.rst b/doc/guides/rel_notes/release_19_11.rst
index 8490d897c..382806229 100644
--- a/doc/guides/rel_notes/release_19_11.rst
+++ b/doc/guides/rel_notes/release_19_11.rst
@@ -21,6 +21,10 @@  DPDK Release 19.11
 
       xdg-open build/doc/html/guides/rel_notes/release_19_11.html
 
+* **Updated the ICE driver.**
+
+  * Added support for handling Receive Flex Descriptor.
+  * Added support for protocol extraction on per Rx queue.
 
 New Features
 ------------
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index ae53c2646..4a279f196 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -82,4 +82,7 @@  ifeq ($(CC_AVX2_SUPPORT), 1)
 endif
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
 
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
+
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
index 44a14cb8a..7c74b6169 100644
--- a/drivers/net/ice/ice_ethdev.c
+++ b/drivers/net/ice/ice_ethdev.c
@@ -19,9 +19,11 @@ 
 
 /* devargs */
 #define ICE_SAFE_MODE_SUPPORT_ARG "safe-mode-support"
+#define ICE_PROTO_XTR_ARG         "proto_xtr"
 
 static const char * const ice_valid_args[] = {
 	ICE_SAFE_MODE_SUPPORT_ARG,
+	ICE_PROTO_XTR_ARG,
 	NULL
 };
 
@@ -257,6 +259,280 @@  ice_init_controlq_parameter(struct ice_hw *hw)
 	hw->mailboxq.sq_buf_size = ICE_MAILBOXQ_BUF_SZ;
 }
 
+static int
+lookup_proto_xtr_type(const char *xtr_name)
+{
+	static struct {
+		const char *name;
+		enum proto_xtr_type type;
+	} xtr_type_map[] = {
+		{ "vlan",      PROTO_XTR_VLAN      },
+		{ "ipv4",      PROTO_XTR_IPV4      },
+		{ "ipv6",      PROTO_XTR_IPV6      },
+		{ "ipv6_flow", PROTO_XTR_IPV6_FLOW },
+		{ "tcp",       PROTO_XTR_TCP       },
+	};
+	uint32_t i;
+
+	for (i = 0; i < RTE_DIM(xtr_type_map); i++) {
+		if (strcmp(xtr_name, xtr_type_map[i].name) == 0)
+			return xtr_type_map[i].type;
+	}
+
+	return -1;
+}
+
+/*
+ * Parse elem, the elem could be single number/range or '(' ')' group
+ * 1) A single number elem, it's just a simple digit. e.g. 9
+ * 2) A single range elem, two digits with a '-' between. e.g. 2-6
+ * 3) A group elem, combines multiple 1) or 2) with '( )'. e.g (0,2-4,6)
+ *    Within group elem, '-' used for a range separator;
+ *                       ',' used for a single number.
+ */
+static int
+parse_queue_set(const char *input, int xtr_type, struct ice_devargs *devargs)
+{
+	const char *str = input;
+	char *end = NULL;
+	uint32_t min, max;
+	uint32_t idx;
+
+	while (isblank(*str))
+		str++;
+
+	if (!isdigit(*str) && *str != '(')
+		return -1;
+
+	/* process single number or single range of number */
+	if (*str != '(') {
+		errno = 0;
+		idx = strtoul(str, &end, 10);
+		if (errno || end == NULL || idx >= ICE_MAX_QUEUE_NUM)
+			return -1;
+
+		while (isblank(*end))
+			end++;
+
+		min = idx;
+		max = idx;
+
+		/* process single <number>-<number> */
+		if (*end == '-') {
+			end++;
+			while (isblank(*end))
+				end++;
+			if (!isdigit(*end))
+				return -1;
+
+			errno = 0;
+			idx = strtoul(end, &end, 10);
+			if (errno || end == NULL || idx >= ICE_MAX_QUEUE_NUM)
+				return -1;
+
+			max = idx;
+			while (isblank(*end))
+				end++;
+		}
+
+		if (*end != ':')
+			return -1;
+
+		for (idx = RTE_MIN(min, max);
+		     idx <= RTE_MAX(min, max); idx++)
+			devargs->proto_xtr[idx] = xtr_type;
+
+		return 0;
+	}
+
+	/* process set within bracket */
+	str++;
+	while (isblank(*str))
+		str++;
+	if (*str == '\0')
+		return -1;
+
+	min = ICE_MAX_QUEUE_NUM;
+	do {
+		/* go ahead to the first digit */
+		while (isblank(*str))
+			str++;
+		if (!isdigit(*str))
+			return -1;
+
+		/* get the digit value */
+		errno = 0;
+		idx = strtoul(str, &end, 10);
+		if (errno || end == NULL || idx >= ICE_MAX_QUEUE_NUM)
+			return -1;
+
+		/* go ahead to separator '-',',' and ')' */
+		while (isblank(*end))
+			end++;
+		if (*end == '-') {
+			if (min == ICE_MAX_QUEUE_NUM)
+				min = idx;
+			else /* avoid continuous '-' */
+				return -1;
+		} else if (*end == ',' || *end == ')') {
+			max = idx;
+			if (min == ICE_MAX_QUEUE_NUM)
+				min = idx;
+
+			for (idx = RTE_MIN(min, max);
+			     idx <= RTE_MAX(min, max); idx++)
+				devargs->proto_xtr[idx] = xtr_type;
+
+			min = ICE_MAX_QUEUE_NUM;
+		} else {
+			return -1;
+		}
+
+		str = end + 1;
+	} while (*end != ')' && *end != '\0');
+
+	return 0;
+}
+
+static int
+parse_queue_proto_xtr(const char *queues, struct ice_devargs *devargs)
+{
+	const char *queue_start;
+	uint32_t idx;
+	int xtr_type;
+	char xtr_name[32];
+
+	while (isblank(*queues))
+		queues++;
+
+	if (*queues != '[') {
+		xtr_type = lookup_proto_xtr_type(queues);
+		if (xtr_type < 0)
+			return -1;
+
+		memset(devargs->proto_xtr, xtr_type,
+		       sizeof(devargs->proto_xtr));
+
+		return 0;
+	}
+
+	queues++;
+	do {
+		while (isblank(*queues))
+			queues++;
+		if (*queues == '\0')
+			return -1;
+
+		queue_start = queues;
+
+		/* go across a complete bracket */
+		if (*queue_start == '(') {
+			queues += strcspn(queues, ")");
+			if (*queues != ')')
+				return -1;
+		}
+
+		/* scan the separator ':' */
+		queues += strcspn(queues, ":");
+		if (*queues++ != ':')
+			return -1;
+		while (isblank(*queues))
+			queues++;
+
+		for (idx = 0; ; idx++) {
+			if (isblank(queues[idx]) ||
+			    queues[idx] == ',' ||
+			    queues[idx] == ']' ||
+			    queues[idx] == '\0')
+				break;
+
+			if (idx > sizeof(xtr_name) - 2)
+				return -1;
+
+			xtr_name[idx] = queues[idx];
+		}
+		xtr_name[idx] = '\0';
+		xtr_type = lookup_proto_xtr_type(xtr_name);
+		if (xtr_type < 0)
+			return -1;
+
+		queues += idx;
+
+		while (isblank(*queues) || *queues == ',' || *queues == ']')
+			queues++;
+
+		if (parse_queue_set(queue_start, xtr_type, devargs) < 0)
+			return -1;
+	} while (*queues != '\0');
+
+	return 0;
+}
+
+static int
+handle_proto_xtr_arg(__rte_unused const char *key, const char *value,
+		     void *extra_args)
+{
+	struct ice_devargs *devargs = extra_args;
+
+	if (value == NULL || extra_args == NULL)
+		return -EINVAL;
+
+	if (parse_queue_proto_xtr(value, devargs) < 0) {
+		PMD_DRV_LOG(ERR,
+			    "The protocol extraction parameter is wrong : '%s'",
+			    value);
+		return -1;
+	}
+
+	return 0;
+}
+
+static bool
+ice_proto_xtr_support(struct ice_hw *hw)
+{
+#define FLX_REG(val, fld, idx) \
+	(((val) & GLFLXP_RXDID_FLX_WRD_##idx##_##fld##_M) >> \
+	 GLFLXP_RXDID_FLX_WRD_##idx##_##fld##_S)
+	static struct {
+		uint32_t rxdid;
+		uint16_t protid_0;
+		uint16_t protid_1;
+	} xtr_sets[] = {
+		{ ICE_RXDID_COMMS_AUX_VLAN, ICE_PROT_EVLAN_O, ICE_PROT_VLAN_O },
+		{ ICE_RXDID_COMMS_AUX_IPV4, ICE_PROT_IPV4_OF_OR_S,
+		  ICE_PROT_IPV4_OF_OR_S },
+		{ ICE_RXDID_COMMS_AUX_IPV6, ICE_PROT_IPV6_OF_OR_S,
+		  ICE_PROT_IPV6_OF_OR_S },
+		{ ICE_RXDID_COMMS_AUX_IPV6_FLOW, ICE_PROT_IPV6_OF_OR_S,
+		  ICE_PROT_IPV6_OF_OR_S },
+		{ ICE_RXDID_COMMS_AUX_TCP, ICE_PROT_TCP_IL, ICE_PROT_ID_INVAL },
+	};
+	uint32_t i;
+
+	for (i = 0; i < RTE_DIM(xtr_sets); i++) {
+		uint32_t rxdid = xtr_sets[i].rxdid;
+		uint32_t v;
+
+		if (xtr_sets[i].protid_0 != ICE_PROT_ID_INVAL) {
+			v = ICE_READ_REG(hw, GLFLXP_RXDID_FLX_WRD_4(rxdid));
+
+			if (FLX_REG(v, PROT_MDID, 4) != xtr_sets[i].protid_0 ||
+			    FLX_REG(v, RXDID_OPCODE, 4) != ICE_RX_OPC_EXTRACT)
+				return false;
+		}
+
+		if (xtr_sets[i].protid_1 != ICE_PROT_ID_INVAL) {
+			v = ICE_READ_REG(hw, GLFLXP_RXDID_FLX_WRD_5(rxdid));
+
+			if (FLX_REG(v, PROT_MDID, 5) != xtr_sets[i].protid_1 ||
+			    FLX_REG(v, RXDID_OPCODE, 5) != ICE_RX_OPC_EXTRACT)
+				return false;
+		}
+	}
+
+	return true;
+}
+
 static int
 ice_res_pool_init(struct ice_res_pool_info *pool, uint32_t base,
 		  uint32_t num)
@@ -1079,6 +1355,8 @@  ice_interrupt_handler(void *param)
 static int
 ice_pf_sw_init(struct rte_eth_dev *dev)
 {
+	struct ice_adapter *ad =
+			ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 	struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	struct ice_hw *hw = ICE_PF_TO_HW(pf);
 
@@ -1088,6 +1366,16 @@  ice_pf_sw_init(struct rte_eth_dev *dev)
 
 	pf->lan_nb_qps = pf->lan_nb_qp_max;
 
+	if (ice_proto_xtr_support(hw))
+		pf->proto_xtr = rte_zmalloc(NULL, pf->lan_nb_qps, 0);
+
+	if (pf->proto_xtr != NULL)
+		rte_memcpy(pf->proto_xtr, ad->devargs.proto_xtr,
+			   RTE_MIN((size_t)pf->lan_nb_qps,
+				   sizeof(ad->devargs.proto_xtr)));
+	else
+		PMD_DRV_LOG(NOTICE, "Protocol extraction is disabled");
+
 	return 0;
 }
 
@@ -1378,9 +1666,18 @@  static int ice_parse_devargs(struct rte_eth_dev *dev)
 		return -EINVAL;
 	}
 
+	memset(ad->devargs.proto_xtr, PROTO_XTR_NONE,
+	       sizeof(ad->devargs.proto_xtr));
+
+	ret = rte_kvargs_process(kvlist, ICE_PROTO_XTR_ARG,
+				 &handle_proto_xtr_arg, &ad->devargs);
+	if (ret)
+		goto bail;
+
 	ret = rte_kvargs_process(kvlist, ICE_SAFE_MODE_SUPPORT_ARG,
 				 &parse_bool, &ad->devargs.safe_mode_support);
 
+bail:
 	rte_kvargs_free(kvlist);
 	return ret;
 }
@@ -1547,6 +1844,7 @@  ice_dev_init(struct rte_eth_dev *dev)
 	ice_sched_cleanup_all(hw);
 	rte_free(hw->port_info);
 	ice_shutdown_all_ctrlq(hw);
+	rte_free(pf->proto_xtr);
 
 	return ret;
 }
@@ -1672,6 +1970,8 @@  ice_dev_close(struct rte_eth_dev *dev)
 	rte_free(hw->port_info);
 	hw->port_info = NULL;
 	ice_shutdown_all_ctrlq(hw);
+	rte_free(pf->proto_xtr);
+	pf->proto_xtr = NULL;
 }
 
 static int
@@ -3795,6 +4095,7 @@  RTE_PMD_REGISTER_PCI(net_ice, rte_ice_pmd);
 RTE_PMD_REGISTER_PCI_TABLE(net_ice, pci_id_ice_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_ice, "* igb_uio | uio_pci_generic | vfio-pci");
 RTE_PMD_REGISTER_PARAM_STRING(net_ice,
+			      ICE_PROTO_XTR_ARG "=[queue:]<vlan|ipv4|ipv6|ipv6_flow|tcp>"
 			      ICE_SAFE_MODE_SUPPORT_ARG "=<0|1>");
 
 RTE_INIT(ice_init_log)
diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h
index f569da833..adbb66322 100644
--- a/drivers/net/ice/ice_ethdev.h
+++ b/drivers/net/ice/ice_ethdev.h
@@ -263,6 +263,7 @@  struct ice_pf {
 	uint16_t lan_nb_qp_max;
 	uint16_t lan_nb_qps; /* The number of queue pairs of LAN */
 	uint16_t base_queue; /* The base queue pairs index  in the device */
+	uint8_t *proto_xtr; /* Protocol extraction type for all queues */
 	struct ice_hw_port_stats stats_offset;
 	struct ice_hw_port_stats stats;
 	/* internal packet statistics, it should be excluded from the total */
@@ -273,11 +274,14 @@  struct ice_pf {
 	struct ice_flow_list flow_list;
 };
 
+#define ICE_MAX_QUEUE_NUM  2048
+
 /**
  * Cache devargs parse result.
  */
 struct ice_devargs {
 	int safe_mode_support;
+	uint8_t proto_xtr[ICE_MAX_QUEUE_NUM];
 };
 
 /**
diff --git a/drivers/net/ice/ice_rxtx.c b/drivers/net/ice/ice_rxtx.c
index d2e36853f..e28310b96 100644
--- a/drivers/net/ice/ice_rxtx.c
+++ b/drivers/net/ice/ice_rxtx.c
@@ -13,6 +13,36 @@ 
 		PKT_TX_TCP_SEG |		 \
 		PKT_TX_OUTER_IP_CKSUM)
 
+static inline uint8_t
+ice_rxdid_to_proto_xtr_type(uint8_t rxdid)
+{
+	static uint8_t xtr_map[] = {
+		[ICE_RXDID_COMMS_AUX_VLAN]      = PROTO_XTR_VLAN,
+		[ICE_RXDID_COMMS_AUX_IPV4]      = PROTO_XTR_IPV4,
+		[ICE_RXDID_COMMS_AUX_IPV6]      = PROTO_XTR_IPV6,
+		[ICE_RXDID_COMMS_AUX_IPV6_FLOW] = PROTO_XTR_IPV6_FLOW,
+		[ICE_RXDID_COMMS_AUX_TCP]       = PROTO_XTR_TCP,
+	};
+
+	return rxdid < RTE_DIM(xtr_map) ? xtr_map[rxdid] : PROTO_XTR_NONE;
+}
+
+static inline uint8_t
+ice_proto_xtr_type_to_rxdid(uint8_t xtr_tpye)
+{
+	static uint8_t rxdid_map[] = {
+		[PROTO_XTR_VLAN]      = ICE_RXDID_COMMS_AUX_VLAN,
+		[PROTO_XTR_IPV4]      = ICE_RXDID_COMMS_AUX_IPV4,
+		[PROTO_XTR_IPV6]      = ICE_RXDID_COMMS_AUX_IPV6,
+		[PROTO_XTR_IPV6_FLOW] = ICE_RXDID_COMMS_AUX_IPV6_FLOW,
+		[PROTO_XTR_TCP]       = ICE_RXDID_COMMS_AUX_TCP,
+	};
+	uint8_t rxdid;
+
+	rxdid = xtr_tpye < RTE_DIM(rxdid_map) ? rxdid_map[xtr_tpye] : 0;
+
+	return rxdid != 0 ? rxdid : ICE_RXDID_COMMS_GENERIC;
+}
 
 static enum ice_status
 ice_program_hw_rx_queue(struct ice_rx_queue *rxq)
@@ -84,6 +114,11 @@  ice_program_hw_rx_queue(struct ice_rx_queue *rxq)
 	rx_ctx.showiv = 0;
 	rx_ctx.crcstrip = (rxq->crc_len == 0) ? 1 : 0;
 
+	rxdid = ice_proto_xtr_type_to_rxdid(rxq->proto_xtr);
+
+	PMD_DRV_LOG(DEBUG, "Port (%u) - Rx queue (%u) is set with RXDID : %u",
+		    rxq->port_id, rxq->queue_id, rxdid);
+
 	/* Enable Flexible Descriptors in the queue context which
 	 * allows this driver to select a specific receive descriptor format
 	 */
@@ -641,6 +676,8 @@  ice_rx_queue_setup(struct rte_eth_dev *dev,
 	rxq->drop_en = rx_conf->rx_drop_en;
 	rxq->vsi = vsi;
 	rxq->rx_deferred_start = rx_conf->rx_deferred_start;
+	rxq->proto_xtr = pf->proto_xtr != NULL ?
+			 pf->proto_xtr[queue_idx] : PROTO_XTR_NONE;
 
 	/* Allocate the maximun number of RX ring hardware descriptor. */
 	len = ICE_MAX_RING_DESC;
@@ -1062,6 +1099,10 @@  ice_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union ice_rx_flex_desc *rxdp)
 		   mb->vlan_tci, mb->vlan_tci_outer);
 }
 
+#define ICE_RX_PROTO_XTR_VALID \
+	((1 << ICE_RX_FLEX_DESC_STATUS1_XTRMD4_VALID_S) | \
+	 (1 << ICE_RX_FLEX_DESC_STATUS1_XTRMD5_VALID_S))
+
 static inline void
 ice_rxd_to_pkt_fields(struct rte_mbuf *mb,
 		      volatile union ice_rx_flex_desc *rxdp)
@@ -1075,6 +1116,26 @@  ice_rxd_to_pkt_fields(struct rte_mbuf *mb,
 		mb->ol_flags |= PKT_RX_RSS_HASH;
 		mb->hash.rss = rte_le_to_cpu_32(desc->rss_hash);
 	}
+
+#ifndef RTE_LIBRTE_ICE_16BYTE_RX_DESC
+	init_proto_xtr_flds(mb);
+
+	stat_err = rte_le_to_cpu_16(desc->status_error1);
+	if (stat_err & ICE_RX_PROTO_XTR_VALID) {
+		struct proto_xtr_flds *xtr = get_proto_xtr_flds(mb);
+
+		if (stat_err & (1 << ICE_RX_FLEX_DESC_STATUS1_XTRMD4_VALID_S))
+			xtr->u.raw.data0 =
+				rte_le_to_cpu_16(desc->flex_ts.flex.aux0);
+
+		if (stat_err & (1 << ICE_RX_FLEX_DESC_STATUS1_XTRMD5_VALID_S))
+			xtr->u.raw.data1 =
+				rte_le_to_cpu_16(desc->flex_ts.flex.aux1);
+
+		xtr->type = ice_rxdid_to_proto_xtr_type(desc->rxdid);
+		xtr->magic = PROTO_XTR_MAGIC_ID;
+	}
+#endif
 }
 
 #ifdef RTE_LIBRTE_ICE_RX_ALLOW_BULK_ALLOC
diff --git a/drivers/net/ice/ice_rxtx.h b/drivers/net/ice/ice_rxtx.h
index 64e891875..de16637f3 100644
--- a/drivers/net/ice/ice_rxtx.h
+++ b/drivers/net/ice/ice_rxtx.h
@@ -5,6 +5,7 @@ 
 #ifndef _ICE_RXTX_H_
 #define _ICE_RXTX_H_
 
+#include "rte_pmd_ice.h"
 #include "ice_ethdev.h"
 
 #define ICE_ALIGN_RING_DESC  32
@@ -78,6 +79,7 @@  struct ice_rx_queue {
 	uint16_t max_pkt_len; /* Maximum packet length */
 	bool q_set; /* indicate if rx queue has been configured */
 	bool rx_deferred_start; /* don't start this queue in dev start */
+	uint8_t proto_xtr; /* Protocol extraction from flexible descriptor */
 	ice_rx_release_mbufs_t rx_rel_mbufs;
 };
 
diff --git a/drivers/net/ice/ice_rxtx_vec_common.h b/drivers/net/ice/ice_rxtx_vec_common.h
index c5f0d564f..080ca4175 100644
--- a/drivers/net/ice/ice_rxtx_vec_common.h
+++ b/drivers/net/ice/ice_rxtx_vec_common.h
@@ -234,6 +234,9 @@  ice_rx_vec_queue_default(struct ice_rx_queue *rxq)
 	if (rxq->nb_rx_desc % rxq->rx_free_thresh)
 		return -1;
 
+	if (rxq->proto_xtr != PROTO_XTR_NONE)
+		return -1;
+
 	return 0;
 }
 
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index 36b4b3c85..6828170a9 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -34,3 +34,5 @@  if arch_subdir == 'x86'
 		objs += ice_avx2_lib.extract_objects('ice_rxtx_vec_avx2.c')
 	endif
 endif
+
+install_headers('rte_pmd_ice.h')
diff --git a/drivers/net/ice/rte_pmd_ice.h b/drivers/net/ice/rte_pmd_ice.h
new file mode 100644
index 000000000..719487e1e
--- /dev/null
+++ b/drivers/net/ice/rte_pmd_ice.h
@@ -0,0 +1,152 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#ifndef _RTE_PMD_ICE_H_
+#define _RTE_PMD_ICE_H_
+
+#include <stdio.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum proto_xtr_type {
+	PROTO_XTR_NONE,
+	PROTO_XTR_VLAN,
+	PROTO_XTR_IPV4,
+	PROTO_XTR_IPV6,
+	PROTO_XTR_IPV6_FLOW,
+	PROTO_XTR_TCP,
+};
+
+struct proto_xtr_flds {
+	union {
+		struct {
+			uint16_t data0;
+			uint16_t data1;
+		} raw;
+		struct {
+			uint16_t stag_vid:12,
+				 stag_dei:1,
+				 stag_pcp:3;
+			uint16_t ctag_vid:12,
+				 ctag_dei:1,
+				 ctag_pcp:3;
+		} vlan;
+		struct {
+			uint16_t protocol:8,
+				 ttl:8;
+			uint16_t tos:8,
+				 ihl:4,
+				 version:4;
+		} ipv4;
+		struct {
+			uint16_t hoplimit:8,
+				 nexthdr:8;
+			uint16_t flowhi4:4,
+				 tc:8,
+				 version:4;
+		} ipv6;
+		struct {
+			uint16_t flowlo16;
+			uint16_t flowhi4:4,
+				 tc:8,
+				 version:4;
+		} ipv6_flow;
+		struct {
+			uint16_t fin:1,
+				 syn:1,
+				 rst:1,
+				 psh:1,
+				 ack:1,
+				 urg:1,
+				 ece:1,
+				 cwr:1,
+				 res1:4,
+				 doff:4;
+			uint16_t rsvd;
+		} tcp;
+	} u;
+
+	uint16_t rsvd;
+
+	uint8_t type;
+
+#define PROTO_XTR_MAGIC_ID	0xCE
+	uint8_t magic;
+};
+
+static inline void
+init_proto_xtr_flds(struct rte_mbuf *mb)
+{
+	mb->udata64 = 0;
+}
+
+static inline struct proto_xtr_flds *
+get_proto_xtr_flds(struct rte_mbuf *mb)
+{
+	RTE_BUILD_BUG_ON(sizeof(struct proto_xtr_flds) > sizeof(mb->udata64));
+
+	return (struct proto_xtr_flds *)&mb->udata64;
+}
+
+static inline void
+dump_proto_xtr_flds(struct rte_mbuf *mb)
+{
+	struct proto_xtr_flds *xtr = get_proto_xtr_flds(mb);
+
+	if (xtr->magic != PROTO_XTR_MAGIC_ID || xtr->type == PROTO_XTR_NONE)
+		return;
+
+	printf(" - Protocol Extraction:[0x%04x:0x%04x],",
+	       xtr->u.raw.data0, xtr->u.raw.data1);
+
+	if (xtr->type == PROTO_XTR_VLAN)
+		printf("vlan,stag=%u:%u:%u,ctag=%u:%u:%u ",
+		       xtr->u.vlan.stag_pcp,
+		       xtr->u.vlan.stag_dei,
+		       xtr->u.vlan.stag_vid,
+		       xtr->u.vlan.ctag_pcp,
+		       xtr->u.vlan.ctag_dei,
+		       xtr->u.vlan.ctag_vid);
+	else if (xtr->type == PROTO_XTR_IPV4)
+		printf("ipv4,ver=%u,hdrlen=%u,tos=%u,ttl=%u,proto=%u ",
+		       xtr->u.ipv4.version,
+		       xtr->u.ipv4.ihl,
+		       xtr->u.ipv4.tos,
+		       xtr->u.ipv4.ttl,
+		       xtr->u.ipv4.protocol);
+	else if (xtr->type == PROTO_XTR_IPV6)
+		printf("ipv6,ver=%u,tc=%u,flow_hi4=0x%x,nexthdr=%u,hoplimit=%u ",
+		       xtr->u.ipv6.version,
+		       xtr->u.ipv6.tc,
+		       xtr->u.ipv6.flowhi4,
+		       xtr->u.ipv6.nexthdr,
+		       xtr->u.ipv6.hoplimit);
+	else if (xtr->type == PROTO_XTR_IPV6_FLOW)
+		printf("ipv6_flow,ver=%u,tc=%u,flow=0x%x%04x ",
+		       xtr->u.ipv6_flow.version,
+		       xtr->u.ipv6_flow.tc,
+		       xtr->u.ipv6_flow.flowhi4,
+		       xtr->u.ipv6_flow.flowlo16);
+	else if (xtr->type == PROTO_XTR_TCP)
+		printf("tcp,doff=%u,flags=%s%s%s%s%s%s%s%s ",
+		       xtr->u.tcp.doff,
+		       xtr->u.tcp.cwr ? "C" : "",
+		       xtr->u.tcp.ece ? "E" : "",
+		       xtr->u.tcp.urg ? "U" : "",
+		       xtr->u.tcp.ack ? "A" : "",
+		       xtr->u.tcp.psh ? "P" : "",
+		       xtr->u.tcp.rst ? "R" : "",
+		       xtr->u.tcp.syn ? "S" : "",
+		       xtr->u.tcp.fin ? "F" : "");
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PMD_ICE_H_ */