[dpdk-dev,v2,12/12] examples/l3fwd: add option to parse ptype
Commit Message
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 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.
Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
---
examples/l3fwd/main.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 91 insertions(+)
Comments
Hi Jianfeng,
> -----Original Message-----
> From: Tan, Jianfeng
> Sent: Friday, January 15, 2016 5:46 AM
> To: dev@dpdk.org
> Cc: Zhang, Helin; Ananyev, Konstantin; Tan, Jianfeng
> Subject: [PATCH v2 12/12] examples/l3fwd: add option to parse ptype
>
> 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 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.
>
> Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
> ---
> examples/l3fwd/main.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 91 insertions(+)
>
> diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
> index 5b0c2dd..3c6e1b7 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,13 @@ 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 +2569,74 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
> }
> }
>
> +static int
> +check_packet_type_ok(int portid)
> +{
> + int i, ret;
> + uint32_t *ptypes;
> + int ptype_l3_ipv4 = 0, ptype_l3_ipv6 = 0;
> +
> + ret = rte_eth_dev_get_ptype_info(portid, RTE_PTYPE_L3_MASK, NULL, 0);
> + if (ret <= 0)
> + return 0;
> + ptypes = malloc(sizeof(uint32_t) * ret);
> + rte_eth_dev_get_ptype_info(portid, RTE_PTYPE_L3_MASK,
> + ptypes, ret);
> + 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;
> + }
I think you forgot to do: free(ptypes);
Also, formally speaking malloc can fail here, so probably need to check malloc() return value,
or just allocate ptypes[] on the stack - would be easier.
> +
> + 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;
> + 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);
> + 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;
That's enough for LPM, for EM, don't we need to be sure there are no extensions
in the IP header?
Konstantin
> + 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,14 @@ 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))
> + rte_exit(EXIT_FAILURE,
> + "Failed to add rx callback: port=%d\n",
> + portid);
> +
> }
> }
>
> --
> 2.1.4
Hi Konstantin,
On 1/15/2016 10:47 PM, Ananyev, Konstantin wrote:
> Hi Jianfeng,
>
>> -----Original Message-----
>> From: Tan, Jianfeng
>> Sent: Friday, January 15, 2016 5:46 AM
>> To: dev@dpdk.org
>> Cc: Zhang, Helin; Ananyev, Konstantin; Tan, Jianfeng
>> Subject: [PATCH v2 12/12] examples/l3fwd: add option to parse ptype
>>
>> 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 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.
>>
>> Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
>> ---
>> examples/l3fwd/main.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 91 insertions(+)
>>
...
>> +static inline void
>> +parse_packet_type(struct rte_mbuf *m)
>> +{
>> + struct ether_hdr *eth_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);
>> + 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;
> That's enough for LPM, for EM, don't we need to be sure there are no extensions
> in the IP header?
>
> Konstantin
Yes, EM needs to differentiate RTE_PTYPE_L3_IPV4/RTE_PTYPE_L3_IPV4_EXT,
RTE_PTYPE_L3_IPV6/RTE_PTYPE_L3_IPV6_EXT:
a. for soft ptype parser here, I'll add the code to do it.
b. for hardware ptype parser, things become complex:
those NICs which can differentiate:
e1000
fmf10k
ixgbe
those NICs which cannot differentiate:
cxgbe (ipv4, ipv6)
enic (ipv4, ipv6)
i40e (ipv4_ext_unknown, ipv6_ext_unknown)
mlx4 (ipv4, ipv6)
mlx5 (ipv4, ipv6)
nfp (ipv4, ipv6, ipv6_ext)
vmxnet3 (ipv4, ipv4_ext)
As a result, l3fwd can only work perfectly on those NICs which can
differentiate.
SO if we really do the strict checking?
Thanks,
Jianfeng
Hi Jianfeng,
> -----Original Message-----
> From: Tan, Jianfeng
> Sent: Thursday, February 25, 2016 10:41 AM
> To: Ananyev, Konstantin; dev@dpdk.org
> Cc: Zhang, Helin
> Subject: Re: [PATCH v2 12/12] examples/l3fwd: add option to parse ptype
>
> Hi Konstantin,
>
> On 1/15/2016 10:47 PM, Ananyev, Konstantin wrote:
> > Hi Jianfeng,
> >
> >> -----Original Message-----
> >> From: Tan, Jianfeng
> >> Sent: Friday, January 15, 2016 5:46 AM
> >> To: dev@dpdk.org
> >> Cc: Zhang, Helin; Ananyev, Konstantin; Tan, Jianfeng
> >> Subject: [PATCH v2 12/12] examples/l3fwd: add option to parse ptype
> >>
> >> 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 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.
> >>
> >> Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
> >> ---
> >> examples/l3fwd/main.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >> 1 file changed, 91 insertions(+)
> >>
> ...
> >> +static inline void
> >> +parse_packet_type(struct rte_mbuf *m)
> >> +{
> >> + struct ether_hdr *eth_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);
> >> + 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;
> > That's enough for LPM, for EM, don't we need to be sure there are no extensions
> > in the IP header?
> >
> > Konstantin
>
> Yes, EM needs to differentiate RTE_PTYPE_L3_IPV4/RTE_PTYPE_L3_IPV4_EXT,
> RTE_PTYPE_L3_IPV6/RTE_PTYPE_L3_IPV6_EXT:
> a. for soft ptype parser here, I'll add the code to do it.
>
> b. for hardware ptype parser, things become complex:
> those NICs which can differentiate:
> e1000
> fmf10k
> ixgbe
> those NICs which cannot differentiate:
> cxgbe (ipv4, ipv6)
> enic (ipv4, ipv6)
> i40e (ipv4_ext_unknown, ipv6_ext_unknown)
Yep, I am aware about that difference between i40e and rest of Intel PMDs :(
> mlx4 (ipv4, ipv6)
> mlx5 (ipv4, ipv6)
> nfp (ipv4, ipv6, ipv6_ext)
> vmxnet3 (ipv4, ipv4_ext)
>
> As a result, l3fwd can only work perfectly on those NICs which can
> differentiate.
Well, we can do a SW parsing for that NICs,
but I presume it might slowdown things quite a bit.
>
> SO if we really do the strict checking?
Ok, but then we probably need to put into SA guide that l3fwd EM
not supposed to work with IP with extentions.
Konstantin
>
> Thanks,
> Jianfeng
@@ -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,13 @@ 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 +2569,74 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
}
}
+static int
+check_packet_type_ok(int portid)
+{
+ int i, ret;
+ uint32_t *ptypes;
+ int ptype_l3_ipv4 = 0, ptype_l3_ipv6 = 0;
+
+ ret = rte_eth_dev_get_ptype_info(portid, RTE_PTYPE_L3_MASK, NULL, 0);
+ if (ret <= 0)
+ return 0;
+ ptypes = malloc(sizeof(uint32_t) * ret);
+ rte_eth_dev_get_ptype_info(portid, RTE_PTYPE_L3_MASK,
+ ptypes, ret);
+ 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;
+ 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);
+ 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,14 @@ 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))
+ rte_exit(EXIT_FAILURE,
+ "Failed to add rx callback: port=%d\n",
+ portid);
+
}
}