Thread (202 messages) 202 messages, 11 authors, 2016-04-06

Re: [PATCH] examples/l3fwd: fix using packet type blindly

From: Tan, Jianfeng <hidden>
Date: 2016-03-01 14:17:50

Hi Konstantin,

On 3/1/2016 9:51 PM, Ananyev, Konstantin wrote:
Hi Jianfeng,
quoted
-----Original Message-----
From: Tan, Jianfeng
Sent: Tuesday, March 01, 2016 1:24 AM
To: dev@dpdk.org
Cc: Zhang, Helin; Ananyev, Konstantin; nelio.laranjeiro@6wind.com; adrien.mazarguil@6wind.com; rahul.lakkireddy@chelsio.com;
pmatilai@redhat.com; Tan, Jianfeng
Subject: [PATCH] examples/l3fwd: fix using packet type blindly

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.
[...]
quoted
+
+	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 1;
Why return here?
You'll miss L4 ptype checks below.
Oops, should be: if (!ptype_l3_ipv4_ext || !ptype_l3_ipv6_ext) return 0; 
and continue check L4 ptype.
quoted
+
+	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;
+
+	return 0;
+}
+
+void
+em_parse_ptype(struct rte_mbuf *m)
+{
+	struct ether_hdr *eth_hdr;
+	uint32_t packet_type = 0;
+	uint16_t ethertype;
+	void *l4;
+	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);
+	l4 = (uint8_t *)eth_hdr + sizeof(struct ether_hdr);
Just curious why l4? It looks like l3 :)
Yes, it's typo, should be l3. Thanks for pointing it out.
quoted
+	switch (ethertype) {
+	case ETHER_TYPE_IPv4:
+		ipv4_hdr = (struct ipv4_hdr *)l4;
+		hdr_len = (ipv4_hdr->version_ihl & IPV4_HDR_IHL_MASK) *
+			  IPV4_IHL_MULTIPLIER;
+		if (hdr_len == sizeof(struct ipv4_hdr) &&
+		    (ipv4_hdr->next_proto_id == IPPROTO_TCP ||
+		     ipv4_hdr->next_proto_id == IPPROTO_UDP))
+			packet_type |= RTE_PTYPE_L3_IPV4;
I think it needs to be something like:
If (hdr_len == sizeof(struct ipv4_hdr)) {
         packet_type = RTE_PTYPE_L3_IPV4;
        if (ipv4_hdr->next_proto_id == IPPROTO_TCP)
	packet_type |= RTE_PTYPE_L4_TCP;
        else if ipv4_hdr->next_proto_id == IPPROTO_UDP)
                 packet_type |= RTE_PTYPE_L4_TCP;
}

And then inside em forward check ptype to be sure that is IPV4 with no options and UDP/TCP packet.
Same for IPv6.
Got it, I'll change it and add this check in em forward function.
quoted
+		break;
+	case ETHER_TYPE_IPv6:
+		ipv6_hdr = (struct ipv6_hdr *)l4;
+		if (ipv6_hdr->proto == IPPROTO_TCP ||
+		    ipv6_hdr->proto == IPPROTO_UDP)
+			packet_type |= RTE_PTYPE_L3_IPV6;
+		break;
+	}
+
+	m->packet_type |= packet_type;
+}
+
  /* main processing loop */
  int
  em_main_loop(__attribute__((unused)) void *dummy)
diff --git a/examples/l3fwd/l3fwd_lpm.c b/examples/l3fwd/l3fwd_lpm.c
index e0ed3c4..981227a 100644
--- a/examples/l3fwd/l3fwd_lpm.c
+++ b/examples/l3fwd/l3fwd_lpm.c
@@ -280,6 +280,63 @@ setup_lpm(const int socketid)
  	}
  }

+int
+lpm_check_ptype(int portid)
+{
+	int i, ret;
+	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;
+
+	uint32_t ptypes[ret];
+
+	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;
+
+}
+
+void
+lpm_parse_ptype(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;
Might be safer:
m->packet_type = packet_type;
Your previous comment on this says that the assignment will write off 
some ptype info PMDs have filled. But for l3fwd, I think it does not 
care other ptype info.

[...]
+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)
+		l3fwd_lkp.parse_ptype(pkts[i]);

No need to create callback chains.
That way you have extra call per packet.
Just 2 callbaclks: cb_lpm_parse_ptype & cb_em_parse_ptype,
and then register one depending on which mode are we in.
Would be simpler and faster, I believe.
Yes, I was considering it too. In addition, shall I use vector 
instruction here to accelerate it?

Thanks,
Jianfeng
Konstantin
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help