1*d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2*d30ea906Sjfb8856606  * Copyright(c) 2017 Intel Corporation
32bfe3f2eSlogwang  */
42bfe3f2eSlogwang 
52bfe3f2eSlogwang #include <stdint.h>
62bfe3f2eSlogwang #include <inttypes.h>
72bfe3f2eSlogwang #include <getopt.h>
82bfe3f2eSlogwang 
92bfe3f2eSlogwang #include <rte_eal.h>
102bfe3f2eSlogwang #include <rte_ethdev.h>
112bfe3f2eSlogwang #include <rte_cycles.h>
122bfe3f2eSlogwang #include <rte_lcore.h>
132bfe3f2eSlogwang #include <rte_mbuf.h>
142bfe3f2eSlogwang #include <rte_flow.h>
152bfe3f2eSlogwang #include <rte_flow_classify.h>
162bfe3f2eSlogwang #include <rte_table_acl.h>
172bfe3f2eSlogwang 
18*d30ea906Sjfb8856606 #define RX_RING_SIZE 1024
19*d30ea906Sjfb8856606 #define TX_RING_SIZE 1024
202bfe3f2eSlogwang 
212bfe3f2eSlogwang #define NUM_MBUFS 8191
222bfe3f2eSlogwang #define MBUF_CACHE_SIZE 250
232bfe3f2eSlogwang #define BURST_SIZE 32
242bfe3f2eSlogwang 
252bfe3f2eSlogwang #define MAX_NUM_CLASSIFY 30
262bfe3f2eSlogwang #define FLOW_CLASSIFY_MAX_RULE_NUM 91
272bfe3f2eSlogwang #define FLOW_CLASSIFY_MAX_PRIORITY 8
282bfe3f2eSlogwang #define FLOW_CLASSIFIER_NAME_SIZE 64
292bfe3f2eSlogwang 
302bfe3f2eSlogwang #define COMMENT_LEAD_CHAR	('#')
312bfe3f2eSlogwang #define OPTION_RULE_IPV4	"rule_ipv4"
322bfe3f2eSlogwang #define RTE_LOGTYPE_FLOW_CLASSIFY	RTE_LOGTYPE_USER3
332bfe3f2eSlogwang #define flow_classify_log(format, ...) \
342bfe3f2eSlogwang 		RTE_LOG(ERR, FLOW_CLASSIFY, format, ##__VA_ARGS__)
352bfe3f2eSlogwang 
362bfe3f2eSlogwang #define uint32_t_to_char(ip, a, b, c, d) do {\
372bfe3f2eSlogwang 		*a = (unsigned char)(ip >> 24 & 0xff);\
382bfe3f2eSlogwang 		*b = (unsigned char)(ip >> 16 & 0xff);\
392bfe3f2eSlogwang 		*c = (unsigned char)(ip >> 8 & 0xff);\
402bfe3f2eSlogwang 		*d = (unsigned char)(ip & 0xff);\
412bfe3f2eSlogwang 	} while (0)
422bfe3f2eSlogwang 
432bfe3f2eSlogwang enum {
442bfe3f2eSlogwang 	CB_FLD_SRC_ADDR,
452bfe3f2eSlogwang 	CB_FLD_DST_ADDR,
462bfe3f2eSlogwang 	CB_FLD_SRC_PORT,
472bfe3f2eSlogwang 	CB_FLD_SRC_PORT_DLM,
482bfe3f2eSlogwang 	CB_FLD_SRC_PORT_MASK,
492bfe3f2eSlogwang 	CB_FLD_DST_PORT,
502bfe3f2eSlogwang 	CB_FLD_DST_PORT_DLM,
512bfe3f2eSlogwang 	CB_FLD_DST_PORT_MASK,
522bfe3f2eSlogwang 	CB_FLD_PROTO,
532bfe3f2eSlogwang 	CB_FLD_PRIORITY,
542bfe3f2eSlogwang 	CB_FLD_NUM,
552bfe3f2eSlogwang };
562bfe3f2eSlogwang 
572bfe3f2eSlogwang static struct{
582bfe3f2eSlogwang 	const char *rule_ipv4_name;
592bfe3f2eSlogwang } parm_config;
602bfe3f2eSlogwang const char cb_port_delim[] = ":";
612bfe3f2eSlogwang 
622bfe3f2eSlogwang static const struct rte_eth_conf port_conf_default = {
63*d30ea906Sjfb8856606 	.rxmode = {
64*d30ea906Sjfb8856606 		.max_rx_pkt_len = ETHER_MAX_LEN,
65*d30ea906Sjfb8856606 	},
662bfe3f2eSlogwang };
672bfe3f2eSlogwang 
682bfe3f2eSlogwang struct flow_classifier {
692bfe3f2eSlogwang 	struct rte_flow_classifier *cls;
702bfe3f2eSlogwang };
712bfe3f2eSlogwang 
722bfe3f2eSlogwang struct flow_classifier_acl {
732bfe3f2eSlogwang 	struct flow_classifier cls;
742bfe3f2eSlogwang } __rte_cache_aligned;
752bfe3f2eSlogwang 
762bfe3f2eSlogwang /* ACL field definitions for IPv4 5 tuple rule */
772bfe3f2eSlogwang 
782bfe3f2eSlogwang enum {
792bfe3f2eSlogwang 	PROTO_FIELD_IPV4,
802bfe3f2eSlogwang 	SRC_FIELD_IPV4,
812bfe3f2eSlogwang 	DST_FIELD_IPV4,
822bfe3f2eSlogwang 	SRCP_FIELD_IPV4,
832bfe3f2eSlogwang 	DSTP_FIELD_IPV4,
842bfe3f2eSlogwang 	NUM_FIELDS_IPV4
852bfe3f2eSlogwang };
862bfe3f2eSlogwang 
872bfe3f2eSlogwang enum {
882bfe3f2eSlogwang 	PROTO_INPUT_IPV4,
892bfe3f2eSlogwang 	SRC_INPUT_IPV4,
902bfe3f2eSlogwang 	DST_INPUT_IPV4,
912bfe3f2eSlogwang 	SRCP_DESTP_INPUT_IPV4
922bfe3f2eSlogwang };
932bfe3f2eSlogwang 
942bfe3f2eSlogwang static struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
952bfe3f2eSlogwang 	/* first input field - always one byte long. */
962bfe3f2eSlogwang 	{
972bfe3f2eSlogwang 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
982bfe3f2eSlogwang 		.size = sizeof(uint8_t),
992bfe3f2eSlogwang 		.field_index = PROTO_FIELD_IPV4,
1002bfe3f2eSlogwang 		.input_index = PROTO_INPUT_IPV4,
1012bfe3f2eSlogwang 		.offset = sizeof(struct ether_hdr) +
1022bfe3f2eSlogwang 			offsetof(struct ipv4_hdr, next_proto_id),
1032bfe3f2eSlogwang 	},
1042bfe3f2eSlogwang 	/* next input field (IPv4 source address) - 4 consecutive bytes. */
1052bfe3f2eSlogwang 	{
1062bfe3f2eSlogwang 		/* rte_flow uses a bit mask for IPv4 addresses */
1072bfe3f2eSlogwang 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
1082bfe3f2eSlogwang 		.size = sizeof(uint32_t),
1092bfe3f2eSlogwang 		.field_index = SRC_FIELD_IPV4,
1102bfe3f2eSlogwang 		.input_index = SRC_INPUT_IPV4,
1112bfe3f2eSlogwang 		.offset = sizeof(struct ether_hdr) +
1122bfe3f2eSlogwang 			offsetof(struct ipv4_hdr, src_addr),
1132bfe3f2eSlogwang 	},
1142bfe3f2eSlogwang 	/* next input field (IPv4 destination address) - 4 consecutive bytes. */
1152bfe3f2eSlogwang 	{
1162bfe3f2eSlogwang 		/* rte_flow uses a bit mask for IPv4 addresses */
1172bfe3f2eSlogwang 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
1182bfe3f2eSlogwang 		.size = sizeof(uint32_t),
1192bfe3f2eSlogwang 		.field_index = DST_FIELD_IPV4,
1202bfe3f2eSlogwang 		.input_index = DST_INPUT_IPV4,
1212bfe3f2eSlogwang 		.offset = sizeof(struct ether_hdr) +
1222bfe3f2eSlogwang 			offsetof(struct ipv4_hdr, dst_addr),
1232bfe3f2eSlogwang 	},
1242bfe3f2eSlogwang 	/*
1252bfe3f2eSlogwang 	 * Next 2 fields (src & dst ports) form 4 consecutive bytes.
1262bfe3f2eSlogwang 	 * They share the same input index.
1272bfe3f2eSlogwang 	 */
1282bfe3f2eSlogwang 	{
1292bfe3f2eSlogwang 		/* rte_flow uses a bit mask for protocol ports */
1302bfe3f2eSlogwang 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
1312bfe3f2eSlogwang 		.size = sizeof(uint16_t),
1322bfe3f2eSlogwang 		.field_index = SRCP_FIELD_IPV4,
1332bfe3f2eSlogwang 		.input_index = SRCP_DESTP_INPUT_IPV4,
1342bfe3f2eSlogwang 		.offset = sizeof(struct ether_hdr) +
1352bfe3f2eSlogwang 			sizeof(struct ipv4_hdr) +
1362bfe3f2eSlogwang 			offsetof(struct tcp_hdr, src_port),
1372bfe3f2eSlogwang 	},
1382bfe3f2eSlogwang 	{
1392bfe3f2eSlogwang 		/* rte_flow uses a bit mask for protocol ports */
1402bfe3f2eSlogwang 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
1412bfe3f2eSlogwang 		.size = sizeof(uint16_t),
1422bfe3f2eSlogwang 		.field_index = DSTP_FIELD_IPV4,
1432bfe3f2eSlogwang 		.input_index = SRCP_DESTP_INPUT_IPV4,
1442bfe3f2eSlogwang 		.offset = sizeof(struct ether_hdr) +
1452bfe3f2eSlogwang 			sizeof(struct ipv4_hdr) +
1462bfe3f2eSlogwang 			offsetof(struct tcp_hdr, dst_port),
1472bfe3f2eSlogwang 	},
1482bfe3f2eSlogwang };
1492bfe3f2eSlogwang 
1502bfe3f2eSlogwang /* flow classify data */
1512bfe3f2eSlogwang static int num_classify_rules;
1522bfe3f2eSlogwang static struct rte_flow_classify_rule *rules[MAX_NUM_CLASSIFY];
1532bfe3f2eSlogwang static struct rte_flow_classify_ipv4_5tuple_stats ntuple_stats;
1542bfe3f2eSlogwang static struct rte_flow_classify_stats classify_stats = {
1552bfe3f2eSlogwang 		.stats = (void **)&ntuple_stats
1562bfe3f2eSlogwang };
1572bfe3f2eSlogwang 
1582bfe3f2eSlogwang /* parameters for rte_flow_classify_validate and
1592bfe3f2eSlogwang  * rte_flow_classify_table_entry_add functions
1602bfe3f2eSlogwang  */
1612bfe3f2eSlogwang 
1622bfe3f2eSlogwang static struct rte_flow_item  eth_item = { RTE_FLOW_ITEM_TYPE_ETH,
1632bfe3f2eSlogwang 	0, 0, 0 };
1642bfe3f2eSlogwang static struct rte_flow_item  end_item = { RTE_FLOW_ITEM_TYPE_END,
1652bfe3f2eSlogwang 	0, 0, 0 };
1662bfe3f2eSlogwang 
1672bfe3f2eSlogwang /* sample actions:
1682bfe3f2eSlogwang  * "actions count / end"
1692bfe3f2eSlogwang  */
170*d30ea906Sjfb8856606 struct rte_flow_query_count count = {
171*d30ea906Sjfb8856606 	.reset = 1,
172*d30ea906Sjfb8856606 	.hits_set = 1,
173*d30ea906Sjfb8856606 	.bytes_set = 1,
174*d30ea906Sjfb8856606 	.hits = 0,
175*d30ea906Sjfb8856606 	.bytes = 0,
176*d30ea906Sjfb8856606 };
177*d30ea906Sjfb8856606 static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
178*d30ea906Sjfb8856606 	&count};
1792bfe3f2eSlogwang static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
1802bfe3f2eSlogwang static struct rte_flow_action actions[2];
1812bfe3f2eSlogwang 
1822bfe3f2eSlogwang /* sample attributes */
1832bfe3f2eSlogwang static struct rte_flow_attr attr;
1842bfe3f2eSlogwang 
1852bfe3f2eSlogwang /* flow_classify.c: * Based on DPDK skeleton forwarding example. */
1862bfe3f2eSlogwang 
1872bfe3f2eSlogwang /*
1882bfe3f2eSlogwang  * Initializes a given port using global settings and with the RX buffers
1892bfe3f2eSlogwang  * coming from the mbuf_pool passed as a parameter.
1902bfe3f2eSlogwang  */
1912bfe3f2eSlogwang static inline int
1922bfe3f2eSlogwang port_init(uint8_t port, struct rte_mempool *mbuf_pool)
1932bfe3f2eSlogwang {
1942bfe3f2eSlogwang 	struct rte_eth_conf port_conf = port_conf_default;
1952bfe3f2eSlogwang 	struct ether_addr addr;
1962bfe3f2eSlogwang 	const uint16_t rx_rings = 1, tx_rings = 1;
1972bfe3f2eSlogwang 	int retval;
1982bfe3f2eSlogwang 	uint16_t q;
199*d30ea906Sjfb8856606 	struct rte_eth_dev_info dev_info;
200*d30ea906Sjfb8856606 	struct rte_eth_txconf txconf;
2012bfe3f2eSlogwang 
202*d30ea906Sjfb8856606 	if (!rte_eth_dev_is_valid_port(port))
2032bfe3f2eSlogwang 		return -1;
2042bfe3f2eSlogwang 
205*d30ea906Sjfb8856606 	rte_eth_dev_info_get(port, &dev_info);
206*d30ea906Sjfb8856606 	if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
207*d30ea906Sjfb8856606 		port_conf.txmode.offloads |=
208*d30ea906Sjfb8856606 			DEV_TX_OFFLOAD_MBUF_FAST_FREE;
209*d30ea906Sjfb8856606 
2102bfe3f2eSlogwang 	/* Configure the Ethernet device. */
2112bfe3f2eSlogwang 	retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
2122bfe3f2eSlogwang 	if (retval != 0)
2132bfe3f2eSlogwang 		return retval;
2142bfe3f2eSlogwang 
2152bfe3f2eSlogwang 	/* Allocate and set up 1 RX queue per Ethernet port. */
2162bfe3f2eSlogwang 	for (q = 0; q < rx_rings; q++) {
2172bfe3f2eSlogwang 		retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
2182bfe3f2eSlogwang 				rte_eth_dev_socket_id(port), NULL, mbuf_pool);
2192bfe3f2eSlogwang 		if (retval < 0)
2202bfe3f2eSlogwang 			return retval;
2212bfe3f2eSlogwang 	}
2222bfe3f2eSlogwang 
223*d30ea906Sjfb8856606 	txconf = dev_info.default_txconf;
224*d30ea906Sjfb8856606 	txconf.offloads = port_conf.txmode.offloads;
2252bfe3f2eSlogwang 	/* Allocate and set up 1 TX queue per Ethernet port. */
2262bfe3f2eSlogwang 	for (q = 0; q < tx_rings; q++) {
2272bfe3f2eSlogwang 		retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
228*d30ea906Sjfb8856606 				rte_eth_dev_socket_id(port), &txconf);
2292bfe3f2eSlogwang 		if (retval < 0)
2302bfe3f2eSlogwang 			return retval;
2312bfe3f2eSlogwang 	}
2322bfe3f2eSlogwang 
2332bfe3f2eSlogwang 	/* Start the Ethernet port. */
2342bfe3f2eSlogwang 	retval = rte_eth_dev_start(port);
2352bfe3f2eSlogwang 	if (retval < 0)
2362bfe3f2eSlogwang 		return retval;
2372bfe3f2eSlogwang 
2382bfe3f2eSlogwang 	/* Display the port MAC address. */
2392bfe3f2eSlogwang 	rte_eth_macaddr_get(port, &addr);
2402bfe3f2eSlogwang 	printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
2412bfe3f2eSlogwang 			   " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
2422bfe3f2eSlogwang 			port,
2432bfe3f2eSlogwang 			addr.addr_bytes[0], addr.addr_bytes[1],
2442bfe3f2eSlogwang 			addr.addr_bytes[2], addr.addr_bytes[3],
2452bfe3f2eSlogwang 			addr.addr_bytes[4], addr.addr_bytes[5]);
2462bfe3f2eSlogwang 
2472bfe3f2eSlogwang 	/* Enable RX in promiscuous mode for the Ethernet device. */
2482bfe3f2eSlogwang 	rte_eth_promiscuous_enable(port);
2492bfe3f2eSlogwang 
2502bfe3f2eSlogwang 	return 0;
2512bfe3f2eSlogwang }
2522bfe3f2eSlogwang 
2532bfe3f2eSlogwang /*
2542bfe3f2eSlogwang  * The lcore main. This is the main thread that does the work, reading from
2552bfe3f2eSlogwang  * an input port classifying the packets and writing to an output port.
2562bfe3f2eSlogwang  */
2572bfe3f2eSlogwang static __attribute__((noreturn)) void
2582bfe3f2eSlogwang lcore_main(struct flow_classifier *cls_app)
2592bfe3f2eSlogwang {
260*d30ea906Sjfb8856606 	uint16_t port;
2612bfe3f2eSlogwang 	int ret;
2622bfe3f2eSlogwang 	int i = 0;
2632bfe3f2eSlogwang 
2642bfe3f2eSlogwang 	ret = rte_flow_classify_table_entry_delete(cls_app->cls,
265*d30ea906Sjfb8856606 			rules[7]);
2662bfe3f2eSlogwang 	if (ret)
2672bfe3f2eSlogwang 		printf("table_entry_delete failed [7] %d\n\n", ret);
2682bfe3f2eSlogwang 	else
2692bfe3f2eSlogwang 		printf("table_entry_delete succeeded [7]\n\n");
2702bfe3f2eSlogwang 
2712bfe3f2eSlogwang 	/*
2722bfe3f2eSlogwang 	 * Check that the port is on the same NUMA node as the polling thread
2732bfe3f2eSlogwang 	 * for best performance.
2742bfe3f2eSlogwang 	 */
275*d30ea906Sjfb8856606 	RTE_ETH_FOREACH_DEV(port)
2762bfe3f2eSlogwang 		if (rte_eth_dev_socket_id(port) > 0 &&
2772bfe3f2eSlogwang 			rte_eth_dev_socket_id(port) != (int)rte_socket_id()) {
2782bfe3f2eSlogwang 			printf("\n\n");
2792bfe3f2eSlogwang 			printf("WARNING: port %u is on remote NUMA node\n",
2802bfe3f2eSlogwang 			       port);
2812bfe3f2eSlogwang 			printf("to polling thread.\n");
2822bfe3f2eSlogwang 			printf("Performance will not be optimal.\n");
2835af785ecSfengbojiang(姜凤波) 		}
284*d30ea906Sjfb8856606 	printf("\nCore %u forwarding packets. ", rte_lcore_id());
285*d30ea906Sjfb8856606 	printf("[Ctrl+C to quit]\n");
286*d30ea906Sjfb8856606 
2872bfe3f2eSlogwang 	/* Run until the application is quit or killed. */
2882bfe3f2eSlogwang 	for (;;) {
2892bfe3f2eSlogwang 		/*
2902bfe3f2eSlogwang 		 * Receive packets on a port, classify them and forward them
2912bfe3f2eSlogwang 		 * on the paired port.
2922bfe3f2eSlogwang 		 * The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
2932bfe3f2eSlogwang 		 */
294*d30ea906Sjfb8856606 		RTE_ETH_FOREACH_DEV(port) {
2952bfe3f2eSlogwang 			/* Get burst of RX packets, from first port of pair. */
2962bfe3f2eSlogwang 			struct rte_mbuf *bufs[BURST_SIZE];
2972bfe3f2eSlogwang 			const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
2982bfe3f2eSlogwang 					bufs, BURST_SIZE);
2992bfe3f2eSlogwang 
3002bfe3f2eSlogwang 			if (unlikely(nb_rx == 0))
3012bfe3f2eSlogwang 				continue;
3022bfe3f2eSlogwang 
3032bfe3f2eSlogwang 			for (i = 0; i < MAX_NUM_CLASSIFY; i++) {
3042bfe3f2eSlogwang 				if (rules[i]) {
3052bfe3f2eSlogwang 					ret = rte_flow_classifier_query(
3062bfe3f2eSlogwang 						cls_app->cls,
3072bfe3f2eSlogwang 						bufs, nb_rx, rules[i],
3082bfe3f2eSlogwang 						&classify_stats);
3092bfe3f2eSlogwang 					if (ret)
3102bfe3f2eSlogwang 						printf(
3112bfe3f2eSlogwang 							"rule [%d] query failed ret [%d]\n\n",
3122bfe3f2eSlogwang 							i, ret);
3132bfe3f2eSlogwang 					else {
3142bfe3f2eSlogwang 						printf(
3152bfe3f2eSlogwang 						"rule[%d] count=%"PRIu64"\n",
3162bfe3f2eSlogwang 						i, ntuple_stats.counter1);
3172bfe3f2eSlogwang 
3182bfe3f2eSlogwang 						printf("proto = %d\n",
3192bfe3f2eSlogwang 						ntuple_stats.ipv4_5tuple.proto);
3202bfe3f2eSlogwang 					}
3212bfe3f2eSlogwang 				}
3222bfe3f2eSlogwang 			}
3232bfe3f2eSlogwang 
3242bfe3f2eSlogwang 			/* Send burst of TX packets, to second port of pair. */
3252bfe3f2eSlogwang 			const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
3262bfe3f2eSlogwang 					bufs, nb_rx);
3272bfe3f2eSlogwang 
3282bfe3f2eSlogwang 			/* Free any unsent packets. */
3292bfe3f2eSlogwang 			if (unlikely(nb_tx < nb_rx)) {
3302bfe3f2eSlogwang 				uint16_t buf;
3312bfe3f2eSlogwang 
3322bfe3f2eSlogwang 				for (buf = nb_tx; buf < nb_rx; buf++)
3332bfe3f2eSlogwang 					rte_pktmbuf_free(bufs[buf]);
3342bfe3f2eSlogwang 			}
3352bfe3f2eSlogwang 		}
3362bfe3f2eSlogwang 	}
3372bfe3f2eSlogwang }
3382bfe3f2eSlogwang 
3392bfe3f2eSlogwang /*
3402bfe3f2eSlogwang  * Parse IPv4 5 tuple rules file, ipv4_rules_file.txt.
3412bfe3f2eSlogwang  * Expected format:
3422bfe3f2eSlogwang  * <src_ipv4_addr>'/'<masklen> <space> \
3432bfe3f2eSlogwang  * <dst_ipv4_addr>'/'<masklen> <space> \
3442bfe3f2eSlogwang  * <src_port> <space> ":" <src_port_mask> <space> \
3452bfe3f2eSlogwang  * <dst_port> <space> ":" <dst_port_mask> <space> \
3462bfe3f2eSlogwang  * <proto>'/'<proto_mask> <space> \
3472bfe3f2eSlogwang  * <priority>
3482bfe3f2eSlogwang  */
3492bfe3f2eSlogwang 
3502bfe3f2eSlogwang static int
3512bfe3f2eSlogwang get_cb_field(char **in, uint32_t *fd, int base, unsigned long lim,
3522bfe3f2eSlogwang 		char dlm)
3532bfe3f2eSlogwang {
3542bfe3f2eSlogwang 	unsigned long val;
3552bfe3f2eSlogwang 	char *end;
3562bfe3f2eSlogwang 
3572bfe3f2eSlogwang 	errno = 0;
3582bfe3f2eSlogwang 	val = strtoul(*in, &end, base);
3592bfe3f2eSlogwang 	if (errno != 0 || end[0] != dlm || val > lim)
3602bfe3f2eSlogwang 		return -EINVAL;
3612bfe3f2eSlogwang 	*fd = (uint32_t)val;
3622bfe3f2eSlogwang 	*in = end + 1;
3632bfe3f2eSlogwang 	return 0;
3642bfe3f2eSlogwang }
3652bfe3f2eSlogwang 
3662bfe3f2eSlogwang static int
3672bfe3f2eSlogwang parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len)
3682bfe3f2eSlogwang {
3692bfe3f2eSlogwang 	uint32_t a, b, c, d, m;
3702bfe3f2eSlogwang 
3712bfe3f2eSlogwang 	if (get_cb_field(&in, &a, 0, UINT8_MAX, '.'))
3722bfe3f2eSlogwang 		return -EINVAL;
3732bfe3f2eSlogwang 	if (get_cb_field(&in, &b, 0, UINT8_MAX, '.'))
3742bfe3f2eSlogwang 		return -EINVAL;
3752bfe3f2eSlogwang 	if (get_cb_field(&in, &c, 0, UINT8_MAX, '.'))
3762bfe3f2eSlogwang 		return -EINVAL;
3772bfe3f2eSlogwang 	if (get_cb_field(&in, &d, 0, UINT8_MAX, '/'))
3782bfe3f2eSlogwang 		return -EINVAL;
3792bfe3f2eSlogwang 	if (get_cb_field(&in, &m, 0, sizeof(uint32_t) * CHAR_BIT, 0))
3802bfe3f2eSlogwang 		return -EINVAL;
3812bfe3f2eSlogwang 
3822bfe3f2eSlogwang 	addr[0] = IPv4(a, b, c, d);
3832bfe3f2eSlogwang 	mask_len[0] = m;
3842bfe3f2eSlogwang 	return 0;
3852bfe3f2eSlogwang }
3862bfe3f2eSlogwang 
3872bfe3f2eSlogwang static int
3882bfe3f2eSlogwang parse_ipv4_5tuple_rule(char *str, struct rte_eth_ntuple_filter *ntuple_filter)
3892bfe3f2eSlogwang {
3902bfe3f2eSlogwang 	int i, ret;
3912bfe3f2eSlogwang 	char *s, *sp, *in[CB_FLD_NUM];
3922bfe3f2eSlogwang 	static const char *dlm = " \t\n";
3932bfe3f2eSlogwang 	int dim = CB_FLD_NUM;
3942bfe3f2eSlogwang 	uint32_t temp;
3952bfe3f2eSlogwang 
3962bfe3f2eSlogwang 	s = str;
3972bfe3f2eSlogwang 	for (i = 0; i != dim; i++, s = NULL) {
3982bfe3f2eSlogwang 		in[i] = strtok_r(s, dlm, &sp);
3992bfe3f2eSlogwang 		if (in[i] == NULL)
4002bfe3f2eSlogwang 			return -EINVAL;
4012bfe3f2eSlogwang 	}
4022bfe3f2eSlogwang 
4032bfe3f2eSlogwang 	ret = parse_ipv4_net(in[CB_FLD_SRC_ADDR],
4042bfe3f2eSlogwang 			&ntuple_filter->src_ip,
4052bfe3f2eSlogwang 			&ntuple_filter->src_ip_mask);
4062bfe3f2eSlogwang 	if (ret != 0) {
4072bfe3f2eSlogwang 		flow_classify_log("failed to read source address/mask: %s\n",
4082bfe3f2eSlogwang 			in[CB_FLD_SRC_ADDR]);
4092bfe3f2eSlogwang 		return ret;
4102bfe3f2eSlogwang 	}
4112bfe3f2eSlogwang 
4122bfe3f2eSlogwang 	ret = parse_ipv4_net(in[CB_FLD_DST_ADDR],
4132bfe3f2eSlogwang 			&ntuple_filter->dst_ip,
4142bfe3f2eSlogwang 			&ntuple_filter->dst_ip_mask);
4152bfe3f2eSlogwang 	if (ret != 0) {
4162bfe3f2eSlogwang 		flow_classify_log("failed to read source address/mask: %s\n",
4172bfe3f2eSlogwang 			in[CB_FLD_DST_ADDR]);
4182bfe3f2eSlogwang 		return ret;
4192bfe3f2eSlogwang 	}
4202bfe3f2eSlogwang 
4212bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_SRC_PORT], &temp, 0, UINT16_MAX, 0))
4222bfe3f2eSlogwang 		return -EINVAL;
4232bfe3f2eSlogwang 	ntuple_filter->src_port = (uint16_t)temp;
4242bfe3f2eSlogwang 
4252bfe3f2eSlogwang 	if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
4262bfe3f2eSlogwang 			sizeof(cb_port_delim)) != 0)
4272bfe3f2eSlogwang 		return -EINVAL;
4282bfe3f2eSlogwang 
4292bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_SRC_PORT_MASK], &temp, 0, UINT16_MAX, 0))
4302bfe3f2eSlogwang 		return -EINVAL;
4312bfe3f2eSlogwang 	ntuple_filter->src_port_mask = (uint16_t)temp;
4322bfe3f2eSlogwang 
4332bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_DST_PORT], &temp, 0, UINT16_MAX, 0))
4342bfe3f2eSlogwang 		return -EINVAL;
4352bfe3f2eSlogwang 	ntuple_filter->dst_port = (uint16_t)temp;
4362bfe3f2eSlogwang 
4372bfe3f2eSlogwang 	if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
4382bfe3f2eSlogwang 			sizeof(cb_port_delim)) != 0)
4392bfe3f2eSlogwang 		return -EINVAL;
4402bfe3f2eSlogwang 
4412bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_DST_PORT_MASK], &temp, 0, UINT16_MAX, 0))
4422bfe3f2eSlogwang 		return -EINVAL;
4432bfe3f2eSlogwang 	ntuple_filter->dst_port_mask = (uint16_t)temp;
4442bfe3f2eSlogwang 
4452bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, '/'))
4462bfe3f2eSlogwang 		return -EINVAL;
4472bfe3f2eSlogwang 	ntuple_filter->proto = (uint8_t)temp;
4482bfe3f2eSlogwang 
4492bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, 0))
4502bfe3f2eSlogwang 		return -EINVAL;
4512bfe3f2eSlogwang 	ntuple_filter->proto_mask = (uint8_t)temp;
4522bfe3f2eSlogwang 
4532bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_PRIORITY], &temp, 0, UINT16_MAX, 0))
4542bfe3f2eSlogwang 		return -EINVAL;
4552bfe3f2eSlogwang 	ntuple_filter->priority = (uint16_t)temp;
4562bfe3f2eSlogwang 	if (ntuple_filter->priority > FLOW_CLASSIFY_MAX_PRIORITY)
4572bfe3f2eSlogwang 		ret = -EINVAL;
4582bfe3f2eSlogwang 
4592bfe3f2eSlogwang 	return ret;
4602bfe3f2eSlogwang }
4612bfe3f2eSlogwang 
4622bfe3f2eSlogwang /* Bypass comment and empty lines */
4632bfe3f2eSlogwang static inline int
4642bfe3f2eSlogwang is_bypass_line(char *buff)
4652bfe3f2eSlogwang {
4662bfe3f2eSlogwang 	int i = 0;
4672bfe3f2eSlogwang 
4682bfe3f2eSlogwang 	/* comment line */
4692bfe3f2eSlogwang 	if (buff[0] == COMMENT_LEAD_CHAR)
4702bfe3f2eSlogwang 		return 1;
4712bfe3f2eSlogwang 	/* empty line */
4722bfe3f2eSlogwang 	while (buff[i] != '\0') {
4732bfe3f2eSlogwang 		if (!isspace(buff[i]))
4742bfe3f2eSlogwang 			return 0;
4752bfe3f2eSlogwang 		i++;
4762bfe3f2eSlogwang 	}
4772bfe3f2eSlogwang 	return 1;
4782bfe3f2eSlogwang }
4792bfe3f2eSlogwang 
4802bfe3f2eSlogwang static uint32_t
4812bfe3f2eSlogwang convert_depth_to_bitmask(uint32_t depth_val)
4822bfe3f2eSlogwang {
4832bfe3f2eSlogwang 	uint32_t bitmask = 0;
4842bfe3f2eSlogwang 	int i, j;
4852bfe3f2eSlogwang 
4862bfe3f2eSlogwang 	for (i = depth_val, j = 0; i > 0; i--, j++)
4872bfe3f2eSlogwang 		bitmask |= (1 << (31 - j));
4882bfe3f2eSlogwang 	return bitmask;
4892bfe3f2eSlogwang }
4902bfe3f2eSlogwang 
4912bfe3f2eSlogwang static int
4922bfe3f2eSlogwang add_classify_rule(struct rte_eth_ntuple_filter *ntuple_filter,
4932bfe3f2eSlogwang 		struct flow_classifier *cls_app)
4942bfe3f2eSlogwang {
4952bfe3f2eSlogwang 	int ret = -1;
4962bfe3f2eSlogwang 	int key_found;
4972bfe3f2eSlogwang 	struct rte_flow_error error;
4982bfe3f2eSlogwang 	struct rte_flow_item_ipv4 ipv4_spec;
4992bfe3f2eSlogwang 	struct rte_flow_item_ipv4 ipv4_mask;
5002bfe3f2eSlogwang 	struct rte_flow_item ipv4_udp_item;
5012bfe3f2eSlogwang 	struct rte_flow_item ipv4_tcp_item;
5022bfe3f2eSlogwang 	struct rte_flow_item ipv4_sctp_item;
5032bfe3f2eSlogwang 	struct rte_flow_item_udp udp_spec;
5042bfe3f2eSlogwang 	struct rte_flow_item_udp udp_mask;
5052bfe3f2eSlogwang 	struct rte_flow_item udp_item;
5062bfe3f2eSlogwang 	struct rte_flow_item_tcp tcp_spec;
5072bfe3f2eSlogwang 	struct rte_flow_item_tcp tcp_mask;
5082bfe3f2eSlogwang 	struct rte_flow_item tcp_item;
5092bfe3f2eSlogwang 	struct rte_flow_item_sctp sctp_spec;
5102bfe3f2eSlogwang 	struct rte_flow_item_sctp sctp_mask;
5112bfe3f2eSlogwang 	struct rte_flow_item sctp_item;
5122bfe3f2eSlogwang 	struct rte_flow_item pattern_ipv4_5tuple[4];
5132bfe3f2eSlogwang 	struct rte_flow_classify_rule *rule;
5142bfe3f2eSlogwang 	uint8_t ipv4_proto;
5152bfe3f2eSlogwang 
5162bfe3f2eSlogwang 	if (num_classify_rules >= MAX_NUM_CLASSIFY) {
5172bfe3f2eSlogwang 		printf(
5182bfe3f2eSlogwang 			"\nINFO:  classify rule capacity %d reached\n",
5192bfe3f2eSlogwang 			num_classify_rules);
5202bfe3f2eSlogwang 		return ret;
5212bfe3f2eSlogwang 	}
5222bfe3f2eSlogwang 
5232bfe3f2eSlogwang 	/* set up parameters for validate and add */
5242bfe3f2eSlogwang 	memset(&ipv4_spec, 0, sizeof(ipv4_spec));
5252bfe3f2eSlogwang 	ipv4_spec.hdr.next_proto_id = ntuple_filter->proto;
5262bfe3f2eSlogwang 	ipv4_spec.hdr.src_addr = ntuple_filter->src_ip;
5272bfe3f2eSlogwang 	ipv4_spec.hdr.dst_addr = ntuple_filter->dst_ip;
5282bfe3f2eSlogwang 	ipv4_proto = ipv4_spec.hdr.next_proto_id;
5292bfe3f2eSlogwang 
5302bfe3f2eSlogwang 	memset(&ipv4_mask, 0, sizeof(ipv4_mask));
5312bfe3f2eSlogwang 	ipv4_mask.hdr.next_proto_id = ntuple_filter->proto_mask;
5322bfe3f2eSlogwang 	ipv4_mask.hdr.src_addr = ntuple_filter->src_ip_mask;
5332bfe3f2eSlogwang 	ipv4_mask.hdr.src_addr =
5342bfe3f2eSlogwang 		convert_depth_to_bitmask(ipv4_mask.hdr.src_addr);
5352bfe3f2eSlogwang 	ipv4_mask.hdr.dst_addr = ntuple_filter->dst_ip_mask;
5362bfe3f2eSlogwang 	ipv4_mask.hdr.dst_addr =
5372bfe3f2eSlogwang 		convert_depth_to_bitmask(ipv4_mask.hdr.dst_addr);
5382bfe3f2eSlogwang 
5392bfe3f2eSlogwang 	switch (ipv4_proto) {
5402bfe3f2eSlogwang 	case IPPROTO_UDP:
5412bfe3f2eSlogwang 		ipv4_udp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
5422bfe3f2eSlogwang 		ipv4_udp_item.spec = &ipv4_spec;
5432bfe3f2eSlogwang 		ipv4_udp_item.mask = &ipv4_mask;
5442bfe3f2eSlogwang 		ipv4_udp_item.last = NULL;
5452bfe3f2eSlogwang 
5462bfe3f2eSlogwang 		udp_spec.hdr.src_port = ntuple_filter->src_port;
5472bfe3f2eSlogwang 		udp_spec.hdr.dst_port = ntuple_filter->dst_port;
5482bfe3f2eSlogwang 		udp_spec.hdr.dgram_len = 0;
5492bfe3f2eSlogwang 		udp_spec.hdr.dgram_cksum = 0;
5502bfe3f2eSlogwang 
5512bfe3f2eSlogwang 		udp_mask.hdr.src_port = ntuple_filter->src_port_mask;
5522bfe3f2eSlogwang 		udp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
5532bfe3f2eSlogwang 		udp_mask.hdr.dgram_len = 0;
5542bfe3f2eSlogwang 		udp_mask.hdr.dgram_cksum = 0;
5552bfe3f2eSlogwang 
5562bfe3f2eSlogwang 		udp_item.type = RTE_FLOW_ITEM_TYPE_UDP;
5572bfe3f2eSlogwang 		udp_item.spec = &udp_spec;
5582bfe3f2eSlogwang 		udp_item.mask = &udp_mask;
5592bfe3f2eSlogwang 		udp_item.last = NULL;
5602bfe3f2eSlogwang 
5612bfe3f2eSlogwang 		attr.priority = ntuple_filter->priority;
5622bfe3f2eSlogwang 		pattern_ipv4_5tuple[1] = ipv4_udp_item;
5632bfe3f2eSlogwang 		pattern_ipv4_5tuple[2] = udp_item;
5642bfe3f2eSlogwang 		break;
5652bfe3f2eSlogwang 	case IPPROTO_TCP:
5662bfe3f2eSlogwang 		ipv4_tcp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
5672bfe3f2eSlogwang 		ipv4_tcp_item.spec = &ipv4_spec;
5682bfe3f2eSlogwang 		ipv4_tcp_item.mask = &ipv4_mask;
5692bfe3f2eSlogwang 		ipv4_tcp_item.last = NULL;
5702bfe3f2eSlogwang 
5712bfe3f2eSlogwang 		memset(&tcp_spec, 0, sizeof(tcp_spec));
5722bfe3f2eSlogwang 		tcp_spec.hdr.src_port = ntuple_filter->src_port;
5732bfe3f2eSlogwang 		tcp_spec.hdr.dst_port = ntuple_filter->dst_port;
5742bfe3f2eSlogwang 
5752bfe3f2eSlogwang 		memset(&tcp_mask, 0, sizeof(tcp_mask));
5762bfe3f2eSlogwang 		tcp_mask.hdr.src_port = ntuple_filter->src_port_mask;
5772bfe3f2eSlogwang 		tcp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
5782bfe3f2eSlogwang 
5792bfe3f2eSlogwang 		tcp_item.type = RTE_FLOW_ITEM_TYPE_TCP;
5802bfe3f2eSlogwang 		tcp_item.spec = &tcp_spec;
5812bfe3f2eSlogwang 		tcp_item.mask = &tcp_mask;
5822bfe3f2eSlogwang 		tcp_item.last = NULL;
5832bfe3f2eSlogwang 
5842bfe3f2eSlogwang 		attr.priority = ntuple_filter->priority;
5852bfe3f2eSlogwang 		pattern_ipv4_5tuple[1] = ipv4_tcp_item;
5862bfe3f2eSlogwang 		pattern_ipv4_5tuple[2] = tcp_item;
5872bfe3f2eSlogwang 		break;
5882bfe3f2eSlogwang 	case IPPROTO_SCTP:
5892bfe3f2eSlogwang 		ipv4_sctp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
5902bfe3f2eSlogwang 		ipv4_sctp_item.spec = &ipv4_spec;
5912bfe3f2eSlogwang 		ipv4_sctp_item.mask = &ipv4_mask;
5922bfe3f2eSlogwang 		ipv4_sctp_item.last = NULL;
5932bfe3f2eSlogwang 
5942bfe3f2eSlogwang 		sctp_spec.hdr.src_port = ntuple_filter->src_port;
5952bfe3f2eSlogwang 		sctp_spec.hdr.dst_port = ntuple_filter->dst_port;
5962bfe3f2eSlogwang 		sctp_spec.hdr.cksum = 0;
5972bfe3f2eSlogwang 		sctp_spec.hdr.tag = 0;
5982bfe3f2eSlogwang 
5992bfe3f2eSlogwang 		sctp_mask.hdr.src_port = ntuple_filter->src_port_mask;
6002bfe3f2eSlogwang 		sctp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
6012bfe3f2eSlogwang 		sctp_mask.hdr.cksum = 0;
6022bfe3f2eSlogwang 		sctp_mask.hdr.tag = 0;
6032bfe3f2eSlogwang 
6042bfe3f2eSlogwang 		sctp_item.type = RTE_FLOW_ITEM_TYPE_SCTP;
6052bfe3f2eSlogwang 		sctp_item.spec = &sctp_spec;
6062bfe3f2eSlogwang 		sctp_item.mask = &sctp_mask;
6072bfe3f2eSlogwang 		sctp_item.last = NULL;
6082bfe3f2eSlogwang 
6092bfe3f2eSlogwang 		attr.priority = ntuple_filter->priority;
6102bfe3f2eSlogwang 		pattern_ipv4_5tuple[1] = ipv4_sctp_item;
6112bfe3f2eSlogwang 		pattern_ipv4_5tuple[2] = sctp_item;
6122bfe3f2eSlogwang 		break;
6132bfe3f2eSlogwang 	default:
6142bfe3f2eSlogwang 		return ret;
6152bfe3f2eSlogwang 	}
6162bfe3f2eSlogwang 
6172bfe3f2eSlogwang 	attr.ingress = 1;
6182bfe3f2eSlogwang 	pattern_ipv4_5tuple[0] = eth_item;
6192bfe3f2eSlogwang 	pattern_ipv4_5tuple[3] = end_item;
6202bfe3f2eSlogwang 	actions[0] = count_action;
6212bfe3f2eSlogwang 	actions[1] = end_action;
6222bfe3f2eSlogwang 
623*d30ea906Sjfb8856606 	/* Validate and add rule */
624*d30ea906Sjfb8856606 	ret = rte_flow_classify_validate(cls_app->cls, &attr,
625*d30ea906Sjfb8856606 			pattern_ipv4_5tuple, actions, &error);
626*d30ea906Sjfb8856606 	if (ret) {
627*d30ea906Sjfb8856606 		printf("table entry validate failed ipv4_proto = %u\n",
628*d30ea906Sjfb8856606 			ipv4_proto);
629*d30ea906Sjfb8856606 		return ret;
630*d30ea906Sjfb8856606 	}
631*d30ea906Sjfb8856606 
6322bfe3f2eSlogwang 	rule = rte_flow_classify_table_entry_add(
633*d30ea906Sjfb8856606 			cls_app->cls, &attr, pattern_ipv4_5tuple,
634*d30ea906Sjfb8856606 			actions, &key_found, &error);
6352bfe3f2eSlogwang 	if (rule == NULL) {
6362bfe3f2eSlogwang 		printf("table entry add failed ipv4_proto = %u\n",
6372bfe3f2eSlogwang 			ipv4_proto);
6382bfe3f2eSlogwang 		ret = -1;
6392bfe3f2eSlogwang 		return ret;
6402bfe3f2eSlogwang 	}
6412bfe3f2eSlogwang 
6422bfe3f2eSlogwang 	rules[num_classify_rules] = rule;
6432bfe3f2eSlogwang 	num_classify_rules++;
6442bfe3f2eSlogwang 	return 0;
6452bfe3f2eSlogwang }
6462bfe3f2eSlogwang 
6472bfe3f2eSlogwang static int
6482bfe3f2eSlogwang add_rules(const char *rule_path, struct flow_classifier *cls_app)
6492bfe3f2eSlogwang {
6502bfe3f2eSlogwang 	FILE *fh;
6512bfe3f2eSlogwang 	char buff[LINE_MAX];
6522bfe3f2eSlogwang 	unsigned int i = 0;
6532bfe3f2eSlogwang 	unsigned int total_num = 0;
6542bfe3f2eSlogwang 	struct rte_eth_ntuple_filter ntuple_filter;
6552bfe3f2eSlogwang 	int ret;
6562bfe3f2eSlogwang 
6572bfe3f2eSlogwang 	fh = fopen(rule_path, "rb");
6582bfe3f2eSlogwang 	if (fh == NULL)
6592bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "%s: fopen %s failed\n", __func__,
6602bfe3f2eSlogwang 			rule_path);
6612bfe3f2eSlogwang 
6622bfe3f2eSlogwang 	ret = fseek(fh, 0, SEEK_SET);
6632bfe3f2eSlogwang 	if (ret)
6642bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "%s: fseek %d failed\n", __func__,
6652bfe3f2eSlogwang 			ret);
6662bfe3f2eSlogwang 
6672bfe3f2eSlogwang 	i = 0;
6682bfe3f2eSlogwang 	while (fgets(buff, LINE_MAX, fh) != NULL) {
6692bfe3f2eSlogwang 		i++;
6702bfe3f2eSlogwang 
6712bfe3f2eSlogwang 		if (is_bypass_line(buff))
6722bfe3f2eSlogwang 			continue;
6732bfe3f2eSlogwang 
6742bfe3f2eSlogwang 		if (total_num >= FLOW_CLASSIFY_MAX_RULE_NUM - 1) {
6752bfe3f2eSlogwang 			printf("\nINFO: classify rule capacity %d reached\n",
6762bfe3f2eSlogwang 				total_num);
6772bfe3f2eSlogwang 			break;
6782bfe3f2eSlogwang 		}
6792bfe3f2eSlogwang 
6802bfe3f2eSlogwang 		if (parse_ipv4_5tuple_rule(buff, &ntuple_filter) != 0)
6812bfe3f2eSlogwang 			rte_exit(EXIT_FAILURE,
6822bfe3f2eSlogwang 				"%s Line %u: parse rules error\n",
6832bfe3f2eSlogwang 				rule_path, i);
6842bfe3f2eSlogwang 
6852bfe3f2eSlogwang 		if (add_classify_rule(&ntuple_filter, cls_app) != 0)
6862bfe3f2eSlogwang 			rte_exit(EXIT_FAILURE, "add rule error\n");
6872bfe3f2eSlogwang 
6882bfe3f2eSlogwang 		total_num++;
6892bfe3f2eSlogwang 	}
6902bfe3f2eSlogwang 
6912bfe3f2eSlogwang 	fclose(fh);
6922bfe3f2eSlogwang 	return 0;
6932bfe3f2eSlogwang }
6942bfe3f2eSlogwang 
6952bfe3f2eSlogwang /* display usage */
6962bfe3f2eSlogwang static void
6972bfe3f2eSlogwang print_usage(const char *prgname)
6982bfe3f2eSlogwang {
6992bfe3f2eSlogwang 	printf("%s usage:\n", prgname);
7002bfe3f2eSlogwang 	printf("[EAL options] --  --"OPTION_RULE_IPV4"=FILE: ");
7012bfe3f2eSlogwang 	printf("specify the ipv4 rules file.\n");
7022bfe3f2eSlogwang 	printf("Each rule occupies one line in the file.\n");
7032bfe3f2eSlogwang }
7042bfe3f2eSlogwang 
7052bfe3f2eSlogwang /* Parse the argument given in the command line of the application */
7062bfe3f2eSlogwang static int
7072bfe3f2eSlogwang parse_args(int argc, char **argv)
7082bfe3f2eSlogwang {
7092bfe3f2eSlogwang 	int opt, ret;
7102bfe3f2eSlogwang 	char **argvopt;
7112bfe3f2eSlogwang 	int option_index;
7122bfe3f2eSlogwang 	char *prgname = argv[0];
7132bfe3f2eSlogwang 	static struct option lgopts[] = {
7142bfe3f2eSlogwang 		{OPTION_RULE_IPV4, 1, 0, 0},
7152bfe3f2eSlogwang 		{NULL, 0, 0, 0}
7162bfe3f2eSlogwang 	};
7172bfe3f2eSlogwang 
7182bfe3f2eSlogwang 	argvopt = argv;
7192bfe3f2eSlogwang 
7202bfe3f2eSlogwang 	while ((opt = getopt_long(argc, argvopt, "",
7212bfe3f2eSlogwang 				lgopts, &option_index)) != EOF) {
7222bfe3f2eSlogwang 
7232bfe3f2eSlogwang 		switch (opt) {
7242bfe3f2eSlogwang 		/* long options */
7252bfe3f2eSlogwang 		case 0:
7262bfe3f2eSlogwang 			if (!strncmp(lgopts[option_index].name,
7272bfe3f2eSlogwang 					OPTION_RULE_IPV4,
7282bfe3f2eSlogwang 					sizeof(OPTION_RULE_IPV4)))
7292bfe3f2eSlogwang 				parm_config.rule_ipv4_name = optarg;
7302bfe3f2eSlogwang 			break;
7312bfe3f2eSlogwang 		default:
7322bfe3f2eSlogwang 			print_usage(prgname);
7332bfe3f2eSlogwang 			return -1;
7342bfe3f2eSlogwang 		}
7352bfe3f2eSlogwang 	}
7362bfe3f2eSlogwang 
7372bfe3f2eSlogwang 	if (optind >= 0)
7382bfe3f2eSlogwang 		argv[optind-1] = prgname;
7392bfe3f2eSlogwang 
7402bfe3f2eSlogwang 	ret = optind-1;
7412bfe3f2eSlogwang 	optind = 1; /* reset getopt lib */
7422bfe3f2eSlogwang 	return ret;
7432bfe3f2eSlogwang }
7442bfe3f2eSlogwang 
7452bfe3f2eSlogwang /*
7462bfe3f2eSlogwang  * The main function, which does initialization and calls the lcore_main
7472bfe3f2eSlogwang  * function.
7482bfe3f2eSlogwang  */
7492bfe3f2eSlogwang int
7502bfe3f2eSlogwang main(int argc, char *argv[])
7512bfe3f2eSlogwang {
7522bfe3f2eSlogwang 	struct rte_mempool *mbuf_pool;
753*d30ea906Sjfb8856606 	uint16_t nb_ports;
754*d30ea906Sjfb8856606 	uint16_t portid;
7552bfe3f2eSlogwang 	int ret;
7562bfe3f2eSlogwang 	int socket_id;
7572bfe3f2eSlogwang 	struct rte_table_acl_params table_acl_params;
7582bfe3f2eSlogwang 	struct rte_flow_classify_table_params cls_table_params;
7592bfe3f2eSlogwang 	struct flow_classifier *cls_app;
7602bfe3f2eSlogwang 	struct rte_flow_classifier_params cls_params;
7612bfe3f2eSlogwang 	uint32_t size;
7622bfe3f2eSlogwang 
7632bfe3f2eSlogwang 	/* Initialize the Environment Abstraction Layer (EAL). */
7642bfe3f2eSlogwang 	ret = rte_eal_init(argc, argv);
7652bfe3f2eSlogwang 	if (ret < 0)
7662bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
7672bfe3f2eSlogwang 
7682bfe3f2eSlogwang 	argc -= ret;
7692bfe3f2eSlogwang 	argv += ret;
7702bfe3f2eSlogwang 
7712bfe3f2eSlogwang 	/* parse application arguments (after the EAL ones) */
7722bfe3f2eSlogwang 	ret = parse_args(argc, argv);
7732bfe3f2eSlogwang 	if (ret < 0)
7742bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Invalid flow_classify parameters\n");
7752bfe3f2eSlogwang 
7762bfe3f2eSlogwang 	/* Check that there is an even number of ports to send/receive on. */
777*d30ea906Sjfb8856606 	nb_ports = rte_eth_dev_count_avail();
7782bfe3f2eSlogwang 	if (nb_ports < 2 || (nb_ports & 1))
7792bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
7802bfe3f2eSlogwang 
7812bfe3f2eSlogwang 	/* Creates a new mempool in memory to hold the mbufs. */
7822bfe3f2eSlogwang 	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
7832bfe3f2eSlogwang 		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
7842bfe3f2eSlogwang 
7852bfe3f2eSlogwang 	if (mbuf_pool == NULL)
7862bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
7872bfe3f2eSlogwang 
7882bfe3f2eSlogwang 	/* Initialize all ports. */
789*d30ea906Sjfb8856606 	RTE_ETH_FOREACH_DEV(portid)
7902bfe3f2eSlogwang 		if (port_init(portid, mbuf_pool) != 0)
7912bfe3f2eSlogwang 			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n",
7922bfe3f2eSlogwang 					portid);
7932bfe3f2eSlogwang 
7942bfe3f2eSlogwang 	if (rte_lcore_count() > 1)
7952bfe3f2eSlogwang 		printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
7962bfe3f2eSlogwang 
7972bfe3f2eSlogwang 	socket_id = rte_eth_dev_socket_id(0);
7982bfe3f2eSlogwang 
7992bfe3f2eSlogwang 	/* Memory allocation */
8002bfe3f2eSlogwang 	size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct flow_classifier_acl));
8012bfe3f2eSlogwang 	cls_app = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
8022bfe3f2eSlogwang 	if (cls_app == NULL)
8032bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Cannot allocate classifier memory\n");
8042bfe3f2eSlogwang 
8052bfe3f2eSlogwang 	cls_params.name = "flow_classifier";
8062bfe3f2eSlogwang 	cls_params.socket_id = socket_id;
8072bfe3f2eSlogwang 
8082bfe3f2eSlogwang 	cls_app->cls = rte_flow_classifier_create(&cls_params);
8092bfe3f2eSlogwang 	if (cls_app->cls == NULL) {
8102bfe3f2eSlogwang 		rte_free(cls_app);
8112bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Cannot create classifier\n");
8122bfe3f2eSlogwang 	}
8132bfe3f2eSlogwang 
8142bfe3f2eSlogwang 	/* initialise ACL table params */
8152bfe3f2eSlogwang 	table_acl_params.name = "table_acl_ipv4_5tuple";
8162bfe3f2eSlogwang 	table_acl_params.n_rules = FLOW_CLASSIFY_MAX_RULE_NUM;
8172bfe3f2eSlogwang 	table_acl_params.n_rule_fields = RTE_DIM(ipv4_defs);
8182bfe3f2eSlogwang 	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
8192bfe3f2eSlogwang 
8202bfe3f2eSlogwang 	/* initialise table create params */
821*d30ea906Sjfb8856606 	cls_table_params.ops = &rte_table_acl_ops;
822*d30ea906Sjfb8856606 	cls_table_params.arg_create = &table_acl_params;
823*d30ea906Sjfb8856606 	cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
8242bfe3f2eSlogwang 
825*d30ea906Sjfb8856606 	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
8262bfe3f2eSlogwang 	if (ret) {
8272bfe3f2eSlogwang 		rte_flow_classifier_free(cls_app->cls);
8282bfe3f2eSlogwang 		rte_free(cls_app);
8292bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Failed to create classifier table\n");
8302bfe3f2eSlogwang 	}
8312bfe3f2eSlogwang 
8322bfe3f2eSlogwang 	/* read file of IPv4 5 tuple rules and initialize parameters
8332bfe3f2eSlogwang 	 * for rte_flow_classify_validate and rte_flow_classify_table_entry_add
8342bfe3f2eSlogwang 	 * API's.
8352bfe3f2eSlogwang 	 */
8362bfe3f2eSlogwang 	if (add_rules(parm_config.rule_ipv4_name, cls_app)) {
8372bfe3f2eSlogwang 		rte_flow_classifier_free(cls_app->cls);
8382bfe3f2eSlogwang 		rte_free(cls_app);
8392bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Failed to add rules\n");
8402bfe3f2eSlogwang 	}
8412bfe3f2eSlogwang 
8422bfe3f2eSlogwang 	/* Call lcore_main on the master core only. */
8432bfe3f2eSlogwang 	lcore_main(cls_app);
8442bfe3f2eSlogwang 
8452bfe3f2eSlogwang 	return 0;
8462bfe3f2eSlogwang }
847