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

Jianfeng Tan jianfeng.tan at intel.com
Fri Feb 26 01:09:31 CET 2016


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.

Under the mode of EXACT_MATCH, ip packets with extensions or ip packets
which are neither tcp nor udp cannot work well because it needs the 5
tuples to caculate hash.

Signed-off-by: Jianfeng Tan <jianfeng.tan at intel.com>
---
 doc/guides/sample_app_ug/l3_forward.rst |   6 +-
 examples/l3fwd/main.c                   | 128 ++++++++++++++++++++++++++++++++
 2 files changed, 133 insertions(+), 1 deletion(-)

diff --git a/doc/guides/sample_app_ug/l3_forward.rst b/doc/guides/sample_app_ug/l3_forward.rst
index 4ce734b..e0c22e3 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 with this mode.
+
 Packet Forwarding for LPM-based Lookups
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/examples/l3fwd/main.c b/examples/l3fwd/main.c
index 410f72d..738b94a 100644
--- a/examples/l3fwd/main.c
+++ b/examples/l3fwd/main.c
@@ -178,6 +178,8 @@ 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; /**< Parse packet type using rx callback, and */
+			/**< disabled by default */
 
 #if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
 static int ipv6 = 0; /**< ipv6 is false by default. */
@@ -2029,6 +2031,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
@@ -2045,6 +2048,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}
 	};
 
@@ -2132,6 +2136,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:
@@ -2580,6 +2591,111 @@ signal_handler(int signum)
 	}
 }
 
+static int
+check_packet_type_ok(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);
+	/* It is not a perfect pre-check, i.e., IP packets with extension and
+	 * IP packets which are not TCP/UDP, can pass this check, but cannot
+	 * work well at the mode of EXACT_MATCH.
+	 */
+	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:
+#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
+		{
+			int hdr_len;
+			struct ipv4_hdr *hdr;
+
+			hdr = (struct ipv4_hdr *)((uint8_t *)eth_hdr +
+						sizeof(struct ether_hdr));
+			hdr_len = (hdr->version_ihl & IPV4_HDR_IHL_MASK)
+				* IPV4_IHL_MULTIPLIER;
+			/* Exact match uses 5 tuples to calculate hash, so
+			 * adequate packets should not only have no ip header
+			 * extension but also be TCP/UDP packet
+			 */
+			if (hdr_len == sizeof(struct ipv4_hdr) &&
+			    (hdr->next_proto_id == 6 ||
+			     hdr->next_proto_id == 17))
+				packet_type |= RTE_PTYPE_L3_IPV4;
+		}
+#elif (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
+		packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+#endif
+		break;
+	case ETHER_TYPE_IPv6:
+#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH)
+		{
+			struct ipv6_hdr *hdr;
+
+			hdr = (struct ipv6_hdr *)((uint8_t *)eth_hdr +
+						  sizeof(struct ether_hdr));
+			if (hdr->proto == 6 || hdr->proto == 17)
+				packet_type |= RTE_PTYPE_L3_IPV4;
+		}
+
+#elif (APP_LOOKUP_METHOD == APP_LOOKUP_LPM)
+		packet_type |= RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
+#endif
+		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)
 {
@@ -2697,6 +2813,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++;
@@ -2730,6 +2851,13 @@ 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



More information about the dev mailing list