[dpdk-dev,12/12] examples/l3fwd: add option to parse ptype

Message ID 1451544799-70776-13-git-send-email-jianfeng.tan@intel.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Jianfeng Tan Dec. 31, 2015, 6:53 a.m. UTC
  Firstly, use rte_eth_dev_get_ptype_info() API to check if device will
parse needed packet type. If not, specifying the newly added option,
--parse-ptype to do it in the callback softly.

Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
---
 examples/l3fwd/main.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)
  

Comments

Ananyev, Konstantin Jan. 4, 2016, 6:32 p.m. UTC | #1
Hi Jianfeng,
> -----Original Message-----
> From: Tan, Jianfeng
> Sent: Thursday, December 31, 2015 6:53 AM
> To: dev@dpdk.org
> Cc: Zhang, Helin; Ananyev, Konstantin; Tan, Jianfeng
> Subject: [PATCH 12/12] examples/l3fwd: add option to parse ptype
> 
> Firstly, use rte_eth_dev_get_ptype_info() API to check if device will
> parse needed packet type. If not, specifying the newly added option,
> --parse-ptype to do it in the callback softly.
> 
> Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
> ---
>  examples/l3fwd/main.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
> 
> diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
> index 5b0c2dd..ccbdce3 100644
> --- a/examples/l3fwd/main.c
> +++ b/examples/l3fwd/main.c
> @@ -174,6 +174,7 @@ static __m128i val_eth[RTE_MAX_ETHPORTS];
>  static uint32_t enabled_port_mask = 0;
>  static int promiscuous_on = 0; /**< Ports set in promiscuous mode off by default. */
>  static int numa_on = 1; /**< NUMA is enabled by default. */
> +static int parse_ptype = 0; /**< parse packet type using rx callback */
> 
>  #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
>  static int ipv6 = 0; /**< ipv6 is false by default. */
> @@ -2022,6 +2023,7 @@ parse_eth_dest(const char *optarg)
>  #define CMD_LINE_OPT_IPV6 "ipv6"
>  #define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo"
>  #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num"
> +#define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype"
> 
>  /* Parse the argument given in the command line of the application */
>  static int
> @@ -2038,6 +2040,7 @@ parse_args(int argc, char **argv)
>  		{CMD_LINE_OPT_IPV6, 0, 0, 0},
>  		{CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, 0},
>  		{CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, 0},
> +		{CMD_LINE_OPT_PARSE_PTYPE, 0, 0, 0},
>  		{NULL, 0, 0, 0}
>  	};
> 
> @@ -2125,6 +2128,12 @@ parse_args(int argc, char **argv)
>  				}
>  			}
>  #endif
> +			if (!strncmp(lgopts[option_index].name, CMD_LINE_OPT_PARSE_PTYPE,
> +				sizeof(CMD_LINE_OPT_PARSE_PTYPE))) {
> +				printf("soft parse-ptype is enabled \n");
> +				parse_ptype = 1;
> +			}
> +
>  			break;
> 
>  		default:
> @@ -2559,6 +2568,75 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
>  	}
>  }
> 
> +static int
> +check_packet_type_ok(int portid)
> +{
> +	int i;
> +	int ret;
> +	uint32_t ptypes[RTE_PTYPE_L3_MAX_NUM];
> +	int ptype_l3_ipv4 = 0, ptype_l3_ipv6 = 0;
> +
> +	ret = rte_eth_dev_get_ptype_info(portid, RTE_PTYPE_L3_MASK, ptypes);
> +	for (i = 0; i < ret; ++i) {
> +		if (ptypes[i] & RTE_PTYPE_L3_IPV4)
> +			ptype_l3_ipv4 = 1;
> +		if (ptypes[i] & RTE_PTYPE_L3_IPV6)
> +			ptype_l3_ipv6 = 1;
> +	}
> +
> +	if (ptype_l3_ipv4 == 0)
> +		printf("port %d cannot parse RTE_PTYPE_L3_IPV4\n", portid);
> +
> +	if (ptype_l3_ipv6 == 0)
> +		printf("port %d cannot parse RTE_PTYPE_L3_IPV6\n", portid);
> +
> +	if (ptype_l3_ipv4 || ptype_l3_ipv6)
> +		return 1;
> +
> +	return 0;
> +}
> +static inline void
> +parse_packet_type(struct rte_mbuf *m)
> +{
> +	struct ether_hdr *eth_hdr;
> +	struct vlan_hdr *vlan_hdr;
> +	uint32_t packet_type = 0;
> +	uint16_t ethertype;
> +
> +	eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
> +	ethertype = rte_be_to_cpu_16(eth_hdr->ether_type);
> +	if (ethertype == ETHER_TYPE_VLAN) {

I don't think either LPM or EM support packets with VLAN right now.
So, probably there is no need to support it here.

> +		vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
> +		ethertype = rte_be_to_cpu_16(vlan_hdr->eth_proto);
> +	}
> +	switch (ethertype) {
> +	case ETHER_TYPE_IPv4:
> +		packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
> +		break;
> +	case ETHER_TYPE_IPv6:
> +		packet_type |= RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	m->packet_type = packet_type;

Probably:
m->packet_type |= packet_type;
in case HW supports some other packet types.

> +}
> +
> +static uint16_t
> +cb_parse_packet_type(uint8_t port __rte_unused,
> +		uint16_t queue __rte_unused,
> +		struct rte_mbuf *pkts[],
> +		uint16_t nb_pkts,
> +		uint16_t max_pkts __rte_unused,
> +		void *user_param __rte_unused)
> +{
> +	unsigned i;
> +
> +	for (i = 0; i < nb_pkts; ++i)
> +		parse_packet_type(pkts[i]);
> +}
> +
>  int
>  main(int argc, char **argv)
>  {
> @@ -2672,6 +2750,11 @@ main(int argc, char **argv)
>  				rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d, "
>  					"port=%d\n", ret, portid);
> 
> +			if (!check_packet_type_ok(portid) && !parse_ptype)
> +				rte_exit(EXIT_FAILURE,
> +						"port %d cannot parse packet type, please add --%s\n",
> +						portid, CMD_LINE_OPT_PARSE_PTYPE);
> +
>  			qconf = &lcore_conf[lcore_id];
>  			qconf->tx_queue_id[portid] = queueid;
>  			queueid++;
> @@ -2705,6 +2788,9 @@ main(int argc, char **argv)
>  			if (ret < 0)
>  				rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d,"
>  						"port=%d\n", ret, portid);
> +			if (parse_ptype)
> +				rte_eth_add_rx_callback(portid, queueid,
> +						cb_parse_packet_type, NULL);

Need to check return value.
Konstantin

>  		}
>  	}
> 
> --
> 2.1.4
  
Jianfeng Tan Jan. 5, 2016, 2:44 a.m. UTC | #2
> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Tuesday, January 5, 2016 2:32 AM
> To: Tan, Jianfeng; dev@dpdk.org
> Cc: Zhang, Helin
> Subject: RE: [PATCH 12/12] examples/l3fwd: add option to parse ptype
> 
> 
> Hi Jianfeng,
> > -----Original Message-----
> > From: Tan, Jianfeng
> > Sent: Thursday, December 31, 2015 6:53 AM
> > To: dev@dpdk.org
> > Cc: Zhang, Helin; Ananyev, Konstantin; Tan, Jianfeng
> > Subject: [PATCH 12/12] examples/l3fwd: add option to parse ptype
> >
> > Firstly, use rte_eth_dev_get_ptype_info() API to check if device will
> > parse needed packet type. If not, specifying the newly added option,
> > --parse-ptype to do it in the callback softly.
> >
> > Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
> > ---
> >  examples/l3fwd/main.c | 86
> +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 86 insertions(+)
> >
> > diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
> > index 5b0c2dd..ccbdce3 100644
> > --- a/examples/l3fwd/main.c
> > +++ b/examples/l3fwd/main.c
> > @@ -174,6 +174,7 @@ static __m128i val_eth[RTE_MAX_ETHPORTS];
> >  static uint32_t enabled_port_mask = 0;
> >  static int promiscuous_on = 0; /**< Ports set in promiscuous mode off by
> default. */
> >  static int numa_on = 1; /**< NUMA is enabled by default. */
> > +static int parse_ptype = 0; /**< parse packet type using rx callback */
> >
> >  #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
> >  static int ipv6 = 0; /**< ipv6 is false by default. */
> > @@ -2022,6 +2023,7 @@ parse_eth_dest(const char *optarg)
> >  #define CMD_LINE_OPT_IPV6 "ipv6"
> >  #define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo"
> >  #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num"
> > +#define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype"
> >
> >  /* Parse the argument given in the command line of the application */
> >  static int
> > @@ -2038,6 +2040,7 @@ parse_args(int argc, char **argv)
> >  		{CMD_LINE_OPT_IPV6, 0, 0, 0},
> >  		{CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, 0},
> >  		{CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, 0},
> > +		{CMD_LINE_OPT_PARSE_PTYPE, 0, 0, 0},
> >  		{NULL, 0, 0, 0}
> >  	};
> >
> > @@ -2125,6 +2128,12 @@ parse_args(int argc, char **argv)
> >  				}
> >  			}
> >  #endif
> > +			if (!strncmp(lgopts[option_index].name,
> CMD_LINE_OPT_PARSE_PTYPE,
> > +				sizeof(CMD_LINE_OPT_PARSE_PTYPE))) {
> > +				printf("soft parse-ptype is enabled \n");
> > +				parse_ptype = 1;
> > +			}
> > +
> >  			break;
> >
> >  		default:
> > @@ -2559,6 +2568,75 @@ check_all_ports_link_status(uint8_t port_num,
> uint32_t port_mask)
> >  	}
> >  }
> >
> > +static int
> > +check_packet_type_ok(int portid)
> > +{
> > +	int i;
> > +	int ret;
> > +	uint32_t ptypes[RTE_PTYPE_L3_MAX_NUM];
> > +	int ptype_l3_ipv4 = 0, ptype_l3_ipv6 = 0;
> > +
> > +	ret = rte_eth_dev_get_ptype_info(portid, RTE_PTYPE_L3_MASK,
> ptypes);
> > +	for (i = 0; i < ret; ++i) {
> > +		if (ptypes[i] & RTE_PTYPE_L3_IPV4)
> > +			ptype_l3_ipv4 = 1;
> > +		if (ptypes[i] & RTE_PTYPE_L3_IPV6)
> > +			ptype_l3_ipv6 = 1;
> > +	}
> > +
> > +	if (ptype_l3_ipv4 == 0)
> > +		printf("port %d cannot parse RTE_PTYPE_L3_IPV4\n", portid);
> > +
> > +	if (ptype_l3_ipv6 == 0)
> > +		printf("port %d cannot parse RTE_PTYPE_L3_IPV6\n", portid);
> > +
> > +	if (ptype_l3_ipv4 || ptype_l3_ipv6)
> > +		return 1;
> > +
> > +	return 0;
> > +}
> > +static inline void
> > +parse_packet_type(struct rte_mbuf *m)
> > +{
> > +	struct ether_hdr *eth_hdr;
> > +	struct vlan_hdr *vlan_hdr;
> > +	uint32_t packet_type = 0;
> > +	uint16_t ethertype;
> > +
> > +	eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
> > +	ethertype = rte_be_to_cpu_16(eth_hdr->ether_type);
> > +	if (ethertype == ETHER_TYPE_VLAN) {
> 
> I don't think either LPM or EM support packets with VLAN right now.
> So, probably there is no need to support it here.

Good to know. Will remove it.

> 
> > +		vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
> > +		ethertype = rte_be_to_cpu_16(vlan_hdr->eth_proto);
> > +	}
> > +	switch (ethertype) {
> > +	case ETHER_TYPE_IPv4:
> > +		packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
> > +		break;
> > +	case ETHER_TYPE_IPv6:
> > +		packet_type |= RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
> > +		break;
> > +	default:
> > +		break;
> > +	}
> > +
> > +	m->packet_type = packet_type;
> 
> Probably:
> m->packet_type |= packet_type;
> in case HW supports some other packet types.

I agree. Will fix it.

> 
> > +}
> > +
> > +static uint16_t
> > +cb_parse_packet_type(uint8_t port __rte_unused,
> > +		uint16_t queue __rte_unused,
> > +		struct rte_mbuf *pkts[],
> > +		uint16_t nb_pkts,
> > +		uint16_t max_pkts __rte_unused,
> > +		void *user_param __rte_unused)
> > +{
> > +	unsigned i;
> > +
> > +	for (i = 0; i < nb_pkts; ++i)
> > +		parse_packet_type(pkts[i]);
> > +}
> > +
> >  int
> >  main(int argc, char **argv)
> >  {
> > @@ -2672,6 +2750,11 @@ main(int argc, char **argv)
> >  				rte_exit(EXIT_FAILURE,
> "rte_eth_tx_queue_setup: err=%d, "
> >  					"port=%d\n", ret, portid);
> >
> > +			if (!check_packet_type_ok(portid) && !parse_ptype)
> > +				rte_exit(EXIT_FAILURE,
> > +						"port %d cannot parse packet
> type, please add --%s\n",
> > +						portid,
> CMD_LINE_OPT_PARSE_PTYPE);
> > +
> >  			qconf = &lcore_conf[lcore_id];
> >  			qconf->tx_queue_id[portid] = queueid;
> >  			queueid++;
> > @@ -2705,6 +2788,9 @@ main(int argc, char **argv)
> >  			if (ret < 0)
> >  				rte_exit(EXIT_FAILURE,
> "rte_eth_rx_queue_setup: err=%d,"
> >  						"port=%d\n", ret, portid);
> > +			if (parse_ptype)
> > +				rte_eth_add_rx_callback(portid, queueid,
> > +						cb_parse_packet_type,
> NULL);
> 
> Need to check return value.
> Konstantin

Oops, good catch!

> 
> >  		}
> >  	}
> >
> > --
> > 2.1.4
  
Ananyev, Konstantin Jan. 5, 2016, 4:49 p.m. UTC | #3
Hi Jianfeng,

> > >
> > > +static int
> > > +check_packet_type_ok(int portid)
> > > +{
> > > +	int i;
> > > +	int ret;
> > > +	uint32_t ptypes[RTE_PTYPE_L3_MAX_NUM];
> > > +	int ptype_l3_ipv4 = 0, ptype_l3_ipv6 = 0;
> > > +
> > > +	ret = rte_eth_dev_get_ptype_info(portid, RTE_PTYPE_L3_MASK,
> > ptypes);
> > > +	for (i = 0; i < ret; ++i) {
> > > +		if (ptypes[i] & RTE_PTYPE_L3_IPV4)
> > > +			ptype_l3_ipv4 = 1;
> > > +		if (ptypes[i] & RTE_PTYPE_L3_IPV6)
> > > +			ptype_l3_ipv6 = 1;
> > > +	}
> > > +
> > > +	if (ptype_l3_ipv4 == 0)
> > > +		printf("port %d cannot parse RTE_PTYPE_L3_IPV4\n", portid);
> > > +
> > > +	if (ptype_l3_ipv6 == 0)
> > > +		printf("port %d cannot parse RTE_PTYPE_L3_IPV6\n", portid);
> > > +
> > > +	if (ptype_l3_ipv4 || ptype_l3_ipv6)
> > > +		return 1;


Forgot one thing: I think it should be:

if (ptype_l3_ipv4 && ptype_l3_ipv6)
  return 1;
return 0;

or just:

return ptype_l3_ipv4 && ptype_l3_ipv6;

Konstantin
  
Jianfeng Tan Jan. 7, 2016, 1:20 a.m. UTC | #4
Hi Konstantin,

On 1/6/2016 12:49 AM, Ananyev, Konstantin wrote:
> Hi Jianfeng,
>
>>>> +static int
>>>> +check_packet_type_ok(int portid)
>>>> +{
>>>> +	int i;
>>>> +	int ret;
>>>> +	uint32_t ptypes[RTE_PTYPE_L3_MAX_NUM];
>>>> +	int ptype_l3_ipv4 = 0, ptype_l3_ipv6 = 0;
>>>> +
>>>> +	ret = rte_eth_dev_get_ptype_info(portid, RTE_PTYPE_L3_MASK,
>>> ptypes);
>>>> +	for (i = 0; i < ret; ++i) {
>>>> +		if (ptypes[i] & RTE_PTYPE_L3_IPV4)
>>>> +			ptype_l3_ipv4 = 1;
>>>> +		if (ptypes[i] & RTE_PTYPE_L3_IPV6)
>>>> +			ptype_l3_ipv6 = 1;
>>>> +	}
>>>> +
>>>> +	if (ptype_l3_ipv4 == 0)
>>>> +		printf("port %d cannot parse RTE_PTYPE_L3_IPV4\n", portid);
>>>> +
>>>> +	if (ptype_l3_ipv6 == 0)
>>>> +		printf("port %d cannot parse RTE_PTYPE_L3_IPV6\n", portid);
>>>> +
>>>> +	if (ptype_l3_ipv4 || ptype_l3_ipv6)
>>>> +		return 1;
>
> Forgot one thing: I think it should be:
>
> if (ptype_l3_ipv4 && ptype_l3_ipv6)
>    return 1;
> return 0;
>
> or just:
>
> return ptype_l3_ipv4 && ptype_l3_ipv6;

My original thought is: PMDs, like vmxnet3, fills ptype_l3_ipv4, but not 
ptype_l3_ipv6.
If we use "&&", then it would add rx callback to parse ptype whether 
ipv4 or ipv6 traffic is comming.

Thanks,
Jianfeng

>
> Konstantin
  
Ananyev, Konstantin Jan. 7, 2016, 9:44 a.m. UTC | #5
Hi Jianfeng,

> -----Original Message-----
> From: Tan, Jianfeng
> Sent: Thursday, January 07, 2016 1:20 AM
> To: Ananyev, Konstantin; dev@dpdk.org
> Cc: Zhang, Helin
> Subject: Re: [PATCH 12/12] examples/l3fwd: add option to parse ptype
> 
> 
> Hi Konstantin,
> 
> On 1/6/2016 12:49 AM, Ananyev, Konstantin wrote:
> > Hi Jianfeng,
> >
> >>>> +static int
> >>>> +check_packet_type_ok(int portid)
> >>>> +{
> >>>> +	int i;
> >>>> +	int ret;
> >>>> +	uint32_t ptypes[RTE_PTYPE_L3_MAX_NUM];
> >>>> +	int ptype_l3_ipv4 = 0, ptype_l3_ipv6 = 0;
> >>>> +
> >>>> +	ret = rte_eth_dev_get_ptype_info(portid, RTE_PTYPE_L3_MASK,
> >>> ptypes);
> >>>> +	for (i = 0; i < ret; ++i) {
> >>>> +		if (ptypes[i] & RTE_PTYPE_L3_IPV4)
> >>>> +			ptype_l3_ipv4 = 1;
> >>>> +		if (ptypes[i] & RTE_PTYPE_L3_IPV6)
> >>>> +			ptype_l3_ipv6 = 1;
> >>>> +	}
> >>>> +
> >>>> +	if (ptype_l3_ipv4 == 0)
> >>>> +		printf("port %d cannot parse RTE_PTYPE_L3_IPV4\n", portid);
> >>>> +
> >>>> +	if (ptype_l3_ipv6 == 0)
> >>>> +		printf("port %d cannot parse RTE_PTYPE_L3_IPV6\n", portid);
> >>>> +
> >>>> +	if (ptype_l3_ipv4 || ptype_l3_ipv6)
> >>>> +		return 1;
> >
> > Forgot one thing: I think it should be:
> >
> > if (ptype_l3_ipv4 && ptype_l3_ipv6)
> >    return 1;
> > return 0;
> >
> > or just:
> >
> > return ptype_l3_ipv4 && ptype_l3_ipv6;
> 
> My original thought is: PMDs, like vmxnet3, fills ptype_l3_ipv4, but not
> ptype_l3_ipv6.
> If we use "&&", then it would add rx callback to parse ptype whether
> ipv4 or ipv6 traffic is comming.

Yes, I think that's how it should be:
If HW can't recognise either IPV4 or IPV6 packets, then SW parsing needs to be done.
l3fwd relies on PMD to recognise both IPV4 and IPV6 packets properly.
If it can recognise only IPV4, then IPV6 traffic will not be forwarded correctly,
and visa-versa.  
Konstantin

> 
> Thanks,
> Jianfeng
> 
> >
> > Konstantin
  

Patch

diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
index 5b0c2dd..ccbdce3 100644
--- a/examples/l3fwd/main.c
+++ b/examples/l3fwd/main.c
@@ -174,6 +174,7 @@  static __m128i val_eth[RTE_MAX_ETHPORTS];
 static uint32_t enabled_port_mask = 0;
 static int promiscuous_on = 0; /**< Ports set in promiscuous mode off by default. */
 static int numa_on = 1; /**< NUMA is enabled by default. */
+static int parse_ptype = 0; /**< parse packet type using rx callback */
 
 #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
 static int ipv6 = 0; /**< ipv6 is false by default. */
@@ -2022,6 +2023,7 @@  parse_eth_dest(const char *optarg)
 #define CMD_LINE_OPT_IPV6 "ipv6"
 #define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo"
 #define CMD_LINE_OPT_HASH_ENTRY_NUM "hash-entry-num"
+#define CMD_LINE_OPT_PARSE_PTYPE "parse-ptype"
 
 /* Parse the argument given in the command line of the application */
 static int
@@ -2038,6 +2040,7 @@  parse_args(int argc, char **argv)
 		{CMD_LINE_OPT_IPV6, 0, 0, 0},
 		{CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, 0},
 		{CMD_LINE_OPT_HASH_ENTRY_NUM, 1, 0, 0},
+		{CMD_LINE_OPT_PARSE_PTYPE, 0, 0, 0},
 		{NULL, 0, 0, 0}
 	};
 
@@ -2125,6 +2128,12 @@  parse_args(int argc, char **argv)
 				}
 			}
 #endif
+			if (!strncmp(lgopts[option_index].name, CMD_LINE_OPT_PARSE_PTYPE,
+				sizeof(CMD_LINE_OPT_PARSE_PTYPE))) {
+				printf("soft parse-ptype is enabled \n");
+				parse_ptype = 1;
+			}
+
 			break;
 
 		default:
@@ -2559,6 +2568,75 @@  check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
 	}
 }
 
+static int
+check_packet_type_ok(int portid)
+{
+	int i;
+	int ret;
+	uint32_t ptypes[RTE_PTYPE_L3_MAX_NUM];
+	int ptype_l3_ipv4 = 0, ptype_l3_ipv6 = 0;
+
+	ret = rte_eth_dev_get_ptype_info(portid, RTE_PTYPE_L3_MASK, ptypes);
+	for (i = 0; i < ret; ++i) {
+		if (ptypes[i] & RTE_PTYPE_L3_IPV4)
+			ptype_l3_ipv4 = 1;
+		if (ptypes[i] & RTE_PTYPE_L3_IPV6)
+			ptype_l3_ipv6 = 1;
+	}
+
+	if (ptype_l3_ipv4 == 0)
+		printf("port %d cannot parse RTE_PTYPE_L3_IPV4\n", portid);
+
+	if (ptype_l3_ipv6 == 0)
+		printf("port %d cannot parse RTE_PTYPE_L3_IPV6\n", portid);
+
+	if (ptype_l3_ipv4 || ptype_l3_ipv6)
+		return 1;
+
+	return 0;
+}
+static inline void
+parse_packet_type(struct rte_mbuf *m)
+{
+	struct ether_hdr *eth_hdr;
+	struct vlan_hdr *vlan_hdr;
+	uint32_t packet_type = 0;
+	uint16_t ethertype;
+
+	eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
+	ethertype = rte_be_to_cpu_16(eth_hdr->ether_type);
+	if (ethertype == ETHER_TYPE_VLAN) {
+		vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
+		ethertype = rte_be_to_cpu_16(vlan_hdr->eth_proto);
+	}
+	switch (ethertype) {
+	case ETHER_TYPE_IPv4:
+		packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+		break;
+	case ETHER_TYPE_IPv6:
+		packet_type |= RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
+		break;
+	default:
+		break;
+	}
+
+	m->packet_type = packet_type;
+}
+
+static uint16_t
+cb_parse_packet_type(uint8_t port __rte_unused,
+		uint16_t queue __rte_unused,
+		struct rte_mbuf *pkts[],
+		uint16_t nb_pkts,
+		uint16_t max_pkts __rte_unused,
+		void *user_param __rte_unused)
+{
+	unsigned i;
+
+	for (i = 0; i < nb_pkts; ++i)
+		parse_packet_type(pkts[i]);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -2672,6 +2750,11 @@  main(int argc, char **argv)
 				rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d, "
 					"port=%d\n", ret, portid);
 
+			if (!check_packet_type_ok(portid) && !parse_ptype)
+				rte_exit(EXIT_FAILURE,
+						"port %d cannot parse packet type, please add --%s\n",
+						portid, CMD_LINE_OPT_PARSE_PTYPE);
+
 			qconf = &lcore_conf[lcore_id];
 			qconf->tx_queue_id[portid] = queueid;
 			queueid++;
@@ -2705,6 +2788,9 @@  main(int argc, char **argv)
 			if (ret < 0)
 				rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d,"
 						"port=%d\n", ret, portid);
+			if (parse_ptype)
+				rte_eth_add_rx_callback(portid, queueid,
+						cb_parse_packet_type, NULL);
 		}
 	}