[dpdk-dev] [PATCH v2] examples/l3fwd: fix using packet type blindly

2016-03-09 Thread Tan, Jianfeng
Hi Konstantin,

On 3/8/2016 2:51 AM, Ananyev, Konstantin wrote:
> Hi Jianfeng,
>
>> +/* Requirements:
>> + * 1. IP packets without extension;
>> + * 2. L4 payload should be either TCP or UDP.
>> + */
>> +int
>> +em_check_ptype(int portid)
>> +{
>> +int i, ret;
>> +int ptype_l3_ipv4_ext = 0;
>> +int ptype_l3_ipv6_ext = 0;
>> +int ptype_l4_tcp = 0;
>> +int ptype_l4_udp = 0;
>> +
>> +ret = rte_eth_dev_get_ptype_info(portid,
>> + RTE_PTYPE_L3_MASK | RTE_PTYPE_L4_MASK,
>> + NULL, 0);
>> +if (ret <= 0)
>> +return 0;
>> +
>> +uint32_t ptypes[ret];
>> +
>> +ret = rte_eth_dev_get_ptype_info(portid,
>> + RTE_PTYPE_L3_MASK | RTE_PTYPE_L4_MASK,
>> + ptypes, ret);
>> +for (i = 0; i < ret; ++i) {
>> +switch (ptypes[i]) {
>> +case RTE_PTYPE_L3_IPV4_EXT:
>> +ptype_l3_ipv4_ext = 1;
>> +break;
>> +case RTE_PTYPE_L3_IPV6_EXT:
>> +ptype_l3_ipv6_ext = 1;
>> +break;
>> +case RTE_PTYPE_L4_TCP:
>> +ptype_l4_tcp = 1;
>> +break;
>> +case RTE_PTYPE_L4_UDP:
>> +ptype_l4_udp = 1;
>> +break;
>> +}
>> +}
>> +
>> +if (ptype_l3_ipv4_ext == 0)
>> +printf("port %d cannot parse RTE_PTYPE_L3_IPV4_EXT\n", portid);
>> +if (ptype_l3_ipv6_ext == 0)
>> +printf("port %d cannot parse RTE_PTYPE_L3_IPV6_EXT\n", portid);
>> +if (!ptype_l3_ipv4_ext || !ptype_l3_ipv6_ext)
>> +return 0;
>> +
>> +if (ptype_l4_tcp == 0)
>> +printf("port %d cannot parse RTE_PTYPE_L4_TCP\n", portid);
>> +if (ptype_l4_udp == 0)
>> +printf("port %d cannot parse RTE_PTYPE_L4_UDP\n", portid);
>> +if (ptype_l4_tcp || ptype_l4_udp)
>> +return 1;
> Should probably be: if (ptype_l4_tcp && ptype_l4_udp)
> ?

Oops, yes, we need to make it as a strict checking here.

>
>> +
>> +return 0;
>> +}
>> +
>> +static inline void
>> +em_parse_ptype(struct rte_mbuf *m)
>> +{
>> +struct ether_hdr *eth_hdr;
>> +uint32_t packet_type = RTE_PTYPE_UNKNOWN;
>> +uint16_t ethertype;
>> +void *l3;
>> +int hdr_len;
>> +struct ipv4_hdr *ipv4_hdr;
>> +struct ipv6_hdr *ipv6_hdr;
>> +
>> +eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
>> +ethertype = rte_be_to_cpu_16(eth_hdr->ether_type);
> I think you can avoid bswap here, if use constants in BE format
> for comparison instead:
>   
> ethertype = eth_hdr->ether_type;
> switch (ethertype) {
> case (rte_cpu_to_be_16(ETHER_TYPE_IPv4)):
> ...
>
> Same for lpm.

Great advice!

>
>> @@ -612,6 +622,14 @@ parse_args(int argc, char **argv)
>>  return -1;
>>  }
>>  }
>> +
>> +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:
>> @@ -965,6 +983,40 @@ main(int argc, char **argv)
>>  rte_eth_promiscuous_enable(portid);
>>  }
>>
>> +printf("\n");
>> +
>> +for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
>> +if (rte_lcore_is_enabled(lcore_id) == 0)
>> +continue;
>> +qconf = _conf[lcore_id];
>> +for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
>> +portid = qconf->rx_queue_list[queue].port_id;
>> +queueid = qconf->rx_queue_list[queue].queue_id;
>> +
>> +ret = l3fwd_lkp.check_ptype(portid);
>> +if (ret) {
>> +printf("Port %d: built-in packet type info\n",
>> +   portid);
>> +continue;
>> +}
>
> I thought that if parse_ptype != 0 we always want to use a SW parsing,
> no matter does HW support it or not, no?

Thanks for pointing this out. It's actually worth discussion. It depends 
on how --parse-ptype option means:
a. try best to use hw way, if fails, turns to sw way;
b. use sw way no matter hw way is workable.

Way a makes it portable to use the same cmd line of l3fwd for all devices.
Way b makes it more clear for this option.

I am actually more inclined to way b (your suggested way).

> So user can measure what is the performance difference between HW and SW 
> versions?
> Another thing, that I forgot to ask earlier - with ptype querying in place, 
> would we like to set:
> RTE_I40E_INC_VECTOR=y

[dpdk-dev] [PATCH v2] examples/l3fwd: fix using packet type blindly

2016-03-07 Thread Ananyev, Konstantin
Hi Jianfeng,

> 
> +/* Requirements:
> + * 1. IP packets without extension;
> + * 2. L4 payload should be either TCP or UDP.
> + */
> +int
> +em_check_ptype(int portid)
> +{
> + int i, ret;
> + int ptype_l3_ipv4_ext = 0;
> + int ptype_l3_ipv6_ext = 0;
> + int ptype_l4_tcp = 0;
> + int ptype_l4_udp = 0;
> +
> + ret = rte_eth_dev_get_ptype_info(portid,
> +  RTE_PTYPE_L3_MASK | RTE_PTYPE_L4_MASK,
> +  NULL, 0);
> + if (ret <= 0)
> + return 0;
> +
> + uint32_t ptypes[ret];
> +
> + ret = rte_eth_dev_get_ptype_info(portid,
> +  RTE_PTYPE_L3_MASK | RTE_PTYPE_L4_MASK,
> +  ptypes, ret);
> + for (i = 0; i < ret; ++i) {
> + switch (ptypes[i]) {
> + case RTE_PTYPE_L3_IPV4_EXT:
> + ptype_l3_ipv4_ext = 1;
> + break;
> + case RTE_PTYPE_L3_IPV6_EXT:
> + ptype_l3_ipv6_ext = 1;
> + break;
> + case RTE_PTYPE_L4_TCP:
> + ptype_l4_tcp = 1;
> + break;
> + case RTE_PTYPE_L4_UDP:
> + ptype_l4_udp = 1;
> + break;
> + }
> + }
> +
> + if (ptype_l3_ipv4_ext == 0)
> + printf("port %d cannot parse RTE_PTYPE_L3_IPV4_EXT\n", portid);
> + if (ptype_l3_ipv6_ext == 0)
> + printf("port %d cannot parse RTE_PTYPE_L3_IPV6_EXT\n", portid);
> + if (!ptype_l3_ipv4_ext || !ptype_l3_ipv6_ext)
> + return 0;
> +
> + if (ptype_l4_tcp == 0)
> + printf("port %d cannot parse RTE_PTYPE_L4_TCP\n", portid);
> + if (ptype_l4_udp == 0)
> + printf("port %d cannot parse RTE_PTYPE_L4_UDP\n", portid);
> + if (ptype_l4_tcp || ptype_l4_udp)
> + return 1;

Should probably be: if (ptype_l4_tcp && ptype_l4_udp)
?

> +
> + return 0;
> +}
> +
> +static inline void
> +em_parse_ptype(struct rte_mbuf *m)
> +{
> + struct ether_hdr *eth_hdr;
> + uint32_t packet_type = RTE_PTYPE_UNKNOWN;
> + uint16_t ethertype;
> + void *l3;
> + int hdr_len;
> + struct ipv4_hdr *ipv4_hdr;
> + struct ipv6_hdr *ipv6_hdr;
> +
> + eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
> + ethertype = rte_be_to_cpu_16(eth_hdr->ether_type);

I think you can avoid bswap here, if use constants in BE format 
for comparison instead:

ethertype = eth_hdr->ether_type;
switch (ethertype) {
case (rte_cpu_to_be_16(ETHER_TYPE_IPv4)):
...

Same for lpm.

> 
> @@ -612,6 +622,14 @@ parse_args(int argc, char **argv)
>   return -1;
>   }
>   }
> +
> + 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:
> @@ -965,6 +983,40 @@ main(int argc, char **argv)
>   rte_eth_promiscuous_enable(portid);
>   }
> 
> + printf("\n");
> +
> + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
> + if (rte_lcore_is_enabled(lcore_id) == 0)
> + continue;
> + qconf = _conf[lcore_id];
> + for (queue = 0; queue < qconf->n_rx_queue; ++queue) {
> + portid = qconf->rx_queue_list[queue].port_id;
> + queueid = qconf->rx_queue_list[queue].queue_id;
> +
> + ret = l3fwd_lkp.check_ptype(portid);
> + if (ret) {
> + printf("Port %d: built-in packet type info\n",
> +portid);
> + continue;
> + }


I thought that if parse_ptype != 0 we always want to use a SW parsing,
no matter does HW support it or not, no?
So user can measure what is the performance difference between HW and SW 
versions?
Another thing, that I forgot to ask earlier - with ptype querying in place, 
would we like to set:
RTE_I40E_INC_VECTOR=y 
by default?

Konstantin


[dpdk-dev] [PATCH v2] examples/l3fwd: fix using packet type blindly

2016-03-04 Thread Jianfeng Tan
This patch will work on below patch series.
 - [PATCH v6 00/11] Add API to get packet type info

As a example to use ptype info, l3fwd needs firstly to use
rte_eth_dev_get_ptype_info() API to check if device and/or
its PMD driver will parse and fill the needed packet type;
if not, use the newly added option, --parse-ptype, to
analyze it in the callback softly.

As the mode of EXACT_MATCH uses the 5 tuples to caculate
hash, so we narrow down its scope to:
  a. ip packets with no extensions, and
  b. L4 payload should be either tcp or udp.

Note: this patch does not completely solve the issue, "cannot
run l3fwd on virtio or other devices", because hw_ip_checksum
may be not supported by the devices. Currently we can:
  a. remove this requirements;
  b. wait for virtio front end (pmd) to support it.

Signed-off-by: Jianfeng Tan 
---
v2:
 - Add patchset dependence in commit log.
 - Change hardcoded 0 to RTE_PTYPE_UNKNOWN.
 - More accurate em_parse_type.
 - Add restrictions in EM forwarding functions.
 - Define cb directly to avoid too many function calls when do analyze.
 - Some typo fixed.
 - Change the position to call rte_eth_dev_get_ptype_info
   after rte_eth_dev_start().

 doc/guides/rel_notes/release_16_04.rst  |   5 ++
 doc/guides/sample_app_ug/l3_forward.rst |   6 +-
 examples/l3fwd/l3fwd.h  |  14 
 examples/l3fwd/l3fwd_em.c   | 115 
 examples/l3fwd/l3fwd_em.h   |  10 ++-
 examples/l3fwd/l3fwd_em_hlm_sse.h   |  17 +++--
 examples/l3fwd/l3fwd_em_sse.h   |   9 ++-
 examples/l3fwd/l3fwd_lpm.c  |  71 
 examples/l3fwd/main.c   |  52 +++
 9 files changed, 289 insertions(+), 10 deletions(-)

diff --git a/doc/guides/rel_notes/release_16_04.rst 
b/doc/guides/rel_notes/release_16_04.rst
index 64e913d..4d6260e 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -68,6 +68,11 @@ This section should contain bug fixes added to the relevant 
sections. Sample for
   vhost-switch often fails to allocate mbuf when dequeue from vring because it
   wrongly calculates the number of mbufs needed.

+* **examples/l3fwd: Fixed using packet type blindly.**
+
+  l3fwd makes use of packet type information without even query if devices or 
PMDs
+  really set it. For those don't set ptypes, add an option to parse it softly.
+

 EAL
 ~~~
diff --git a/doc/guides/sample_app_ug/l3_forward.rst 
b/doc/guides/sample_app_ug/l3_forward.rst
index 4ce734b..46a1782 100644
--- a/doc/guides/sample_app_ug/l3_forward.rst
+++ b/doc/guides/sample_app_ug/l3_forward.rst
@@ -93,7 +93,7 @@ The application has a number of command line options:

 .. code-block:: console

-./build/l3fwd [EAL options] -- -p PORTMASK [-P]  
--config(port,queue,lcore)[,(port,queue,lcore)] [--enable-jumbo [--max-pkt-len 
PKTLEN]]  [--no-numa][--hash-entry-num][--ipv6]
+./build/l3fwd [EAL options] -- -p PORTMASK [-P]  
--config(port,queue,lcore)[,(port,queue,lcore)] [--enable-jumbo [--max-pkt-len 
PKTLEN]]  [--no-numa][--hash-entry-num][--ipv6] [--parse-ptype]

 where,

@@ -114,6 +114,8 @@ where,

 *   --ipv6: optional, set it if running ipv6 packets

+*   --parse-ptype: optional, set it if use software way to analyze packet type
+
 For example, consider a dual processor socket platform where cores 0-7 and 
16-23 appear on socket 0, while cores 8-15 and 24-31 appear on socket 1.
 Let's say that the programmer wants to use memory from both NUMA nodes, the 
platform has only two ports, one connected to each NUMA node,
 and the programmer wants to use two cores from each processor socket to do the 
packet processing.
@@ -334,6 +336,8 @@ The key code snippet of simple_ipv4_fwd_4pkts() is shown 
below:

 The simple_ipv6_fwd_4pkts() function is similar to the simple_ipv4_fwd_4pkts() 
function.

+Known issue: IP packets with extensions or IP packets which are not TCP/UDP 
cannot work well at this mode.
+
 Packet Forwarding for LPM-based Lookups
 ~~~

diff --git a/examples/l3fwd/l3fwd.h b/examples/l3fwd/l3fwd.h
index da6d369..6ae2454 100644
--- a/examples/l3fwd/l3fwd.h
+++ b/examples/l3fwd/l3fwd.h
@@ -198,6 +198,20 @@ void
 setup_hash(const int socketid);

 int
+em_check_ptype(int portid);
+
+int
+lpm_check_ptype(int portid);
+
+uint16_t
+em_cb_parse_ptype(uint8_t port, uint16_t queue, struct rte_mbuf *pkts[],
+ uint16_t nb_pkts, uint16_t max_pkts, void *user_param);
+
+uint16_t
+lpm_cb_parse_ptype(uint8_t port, uint16_t queue, struct rte_mbuf *pkts[],
+  uint16_t nb_pkts, uint16_t max_pkts, void *user_param);
+
+int
 em_main_loop(__attribute__((unused)) void *dummy);

 int
diff --git a/examples/l3fwd/l3fwd_em.c b/examples/l3fwd/l3fwd_em.c
index f6a65d8..a2d51f0 100644
--- a/examples/l3fwd/l3fwd_em.c
+++ b/examples/l3fwd/l3fwd_em.c
@@ -42,6 +42,7 @@
 #include 
 #include 
 #include 
+#include 

 #include 
 #include 
@@