1*2bfe3f2eSlogwang /*-
2*2bfe3f2eSlogwang  *   BSD LICENSE
3*2bfe3f2eSlogwang  *
4*2bfe3f2eSlogwang  *   Copyright(c) 2017 Intel Corporation. All rights reserved.
5*2bfe3f2eSlogwang  *   All rights reserved.
6*2bfe3f2eSlogwang  *
7*2bfe3f2eSlogwang  *   Redistribution and use in source and binary forms, with or without
8*2bfe3f2eSlogwang  *   modification, are permitted provided that the following conditions
9*2bfe3f2eSlogwang  *   are met:
10*2bfe3f2eSlogwang  *
11*2bfe3f2eSlogwang  *     * Redistributions of source code must retain the above copyright
12*2bfe3f2eSlogwang  *       notice, this list of conditions and the following disclaimer.
13*2bfe3f2eSlogwang  *     * Redistributions in binary form must reproduce the above copyright
14*2bfe3f2eSlogwang  *       notice, this list of conditions and the following disclaimer in
15*2bfe3f2eSlogwang  *       the documentation and/or other materials provided with the
16*2bfe3f2eSlogwang  *       distribution.
17*2bfe3f2eSlogwang  *     * Neither the name of Intel Corporation nor the names of its
18*2bfe3f2eSlogwang  *       contributors may be used to endorse or promote products derived
19*2bfe3f2eSlogwang  *       from this software without specific prior written permission.
20*2bfe3f2eSlogwang  *
21*2bfe3f2eSlogwang  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*2bfe3f2eSlogwang  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*2bfe3f2eSlogwang  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24*2bfe3f2eSlogwang  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25*2bfe3f2eSlogwang  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26*2bfe3f2eSlogwang  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27*2bfe3f2eSlogwang  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28*2bfe3f2eSlogwang  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29*2bfe3f2eSlogwang  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30*2bfe3f2eSlogwang  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31*2bfe3f2eSlogwang  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*2bfe3f2eSlogwang  */
33*2bfe3f2eSlogwang 
34*2bfe3f2eSlogwang #include <stdint.h>
35*2bfe3f2eSlogwang #include <inttypes.h>
36*2bfe3f2eSlogwang #include <getopt.h>
37*2bfe3f2eSlogwang 
38*2bfe3f2eSlogwang #include <rte_eal.h>
39*2bfe3f2eSlogwang #include <rte_ethdev.h>
40*2bfe3f2eSlogwang #include <rte_cycles.h>
41*2bfe3f2eSlogwang #include <rte_lcore.h>
42*2bfe3f2eSlogwang #include <rte_mbuf.h>
43*2bfe3f2eSlogwang #include <rte_flow.h>
44*2bfe3f2eSlogwang #include <rte_flow_classify.h>
45*2bfe3f2eSlogwang #include <rte_table_acl.h>
46*2bfe3f2eSlogwang 
47*2bfe3f2eSlogwang #define RX_RING_SIZE 128
48*2bfe3f2eSlogwang #define TX_RING_SIZE 512
49*2bfe3f2eSlogwang 
50*2bfe3f2eSlogwang #define NUM_MBUFS 8191
51*2bfe3f2eSlogwang #define MBUF_CACHE_SIZE 250
52*2bfe3f2eSlogwang #define BURST_SIZE 32
53*2bfe3f2eSlogwang 
54*2bfe3f2eSlogwang #define MAX_NUM_CLASSIFY 30
55*2bfe3f2eSlogwang #define FLOW_CLASSIFY_MAX_RULE_NUM 91
56*2bfe3f2eSlogwang #define FLOW_CLASSIFY_MAX_PRIORITY 8
57*2bfe3f2eSlogwang #define FLOW_CLASSIFIER_NAME_SIZE 64
58*2bfe3f2eSlogwang 
59*2bfe3f2eSlogwang #define COMMENT_LEAD_CHAR	('#')
60*2bfe3f2eSlogwang #define OPTION_RULE_IPV4	"rule_ipv4"
61*2bfe3f2eSlogwang #define RTE_LOGTYPE_FLOW_CLASSIFY	RTE_LOGTYPE_USER3
62*2bfe3f2eSlogwang #define flow_classify_log(format, ...) \
63*2bfe3f2eSlogwang 		RTE_LOG(ERR, FLOW_CLASSIFY, format, ##__VA_ARGS__)
64*2bfe3f2eSlogwang 
65*2bfe3f2eSlogwang #define uint32_t_to_char(ip, a, b, c, d) do {\
66*2bfe3f2eSlogwang 		*a = (unsigned char)(ip >> 24 & 0xff);\
67*2bfe3f2eSlogwang 		*b = (unsigned char)(ip >> 16 & 0xff);\
68*2bfe3f2eSlogwang 		*c = (unsigned char)(ip >> 8 & 0xff);\
69*2bfe3f2eSlogwang 		*d = (unsigned char)(ip & 0xff);\
70*2bfe3f2eSlogwang 	} while (0)
71*2bfe3f2eSlogwang 
72*2bfe3f2eSlogwang enum {
73*2bfe3f2eSlogwang 	CB_FLD_SRC_ADDR,
74*2bfe3f2eSlogwang 	CB_FLD_DST_ADDR,
75*2bfe3f2eSlogwang 	CB_FLD_SRC_PORT,
76*2bfe3f2eSlogwang 	CB_FLD_SRC_PORT_DLM,
77*2bfe3f2eSlogwang 	CB_FLD_SRC_PORT_MASK,
78*2bfe3f2eSlogwang 	CB_FLD_DST_PORT,
79*2bfe3f2eSlogwang 	CB_FLD_DST_PORT_DLM,
80*2bfe3f2eSlogwang 	CB_FLD_DST_PORT_MASK,
81*2bfe3f2eSlogwang 	CB_FLD_PROTO,
82*2bfe3f2eSlogwang 	CB_FLD_PRIORITY,
83*2bfe3f2eSlogwang 	CB_FLD_NUM,
84*2bfe3f2eSlogwang };
85*2bfe3f2eSlogwang 
86*2bfe3f2eSlogwang static struct{
87*2bfe3f2eSlogwang 	const char *rule_ipv4_name;
88*2bfe3f2eSlogwang } parm_config;
89*2bfe3f2eSlogwang const char cb_port_delim[] = ":";
90*2bfe3f2eSlogwang 
91*2bfe3f2eSlogwang static const struct rte_eth_conf port_conf_default = {
92*2bfe3f2eSlogwang 	.rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
93*2bfe3f2eSlogwang };
94*2bfe3f2eSlogwang 
95*2bfe3f2eSlogwang struct flow_classifier {
96*2bfe3f2eSlogwang 	struct rte_flow_classifier *cls;
97*2bfe3f2eSlogwang 	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
98*2bfe3f2eSlogwang };
99*2bfe3f2eSlogwang 
100*2bfe3f2eSlogwang struct flow_classifier_acl {
101*2bfe3f2eSlogwang 	struct flow_classifier cls;
102*2bfe3f2eSlogwang } __rte_cache_aligned;
103*2bfe3f2eSlogwang 
104*2bfe3f2eSlogwang /* ACL field definitions for IPv4 5 tuple rule */
105*2bfe3f2eSlogwang 
106*2bfe3f2eSlogwang enum {
107*2bfe3f2eSlogwang 	PROTO_FIELD_IPV4,
108*2bfe3f2eSlogwang 	SRC_FIELD_IPV4,
109*2bfe3f2eSlogwang 	DST_FIELD_IPV4,
110*2bfe3f2eSlogwang 	SRCP_FIELD_IPV4,
111*2bfe3f2eSlogwang 	DSTP_FIELD_IPV4,
112*2bfe3f2eSlogwang 	NUM_FIELDS_IPV4
113*2bfe3f2eSlogwang };
114*2bfe3f2eSlogwang 
115*2bfe3f2eSlogwang enum {
116*2bfe3f2eSlogwang 	PROTO_INPUT_IPV4,
117*2bfe3f2eSlogwang 	SRC_INPUT_IPV4,
118*2bfe3f2eSlogwang 	DST_INPUT_IPV4,
119*2bfe3f2eSlogwang 	SRCP_DESTP_INPUT_IPV4
120*2bfe3f2eSlogwang };
121*2bfe3f2eSlogwang 
122*2bfe3f2eSlogwang static struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
123*2bfe3f2eSlogwang 	/* first input field - always one byte long. */
124*2bfe3f2eSlogwang 	{
125*2bfe3f2eSlogwang 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
126*2bfe3f2eSlogwang 		.size = sizeof(uint8_t),
127*2bfe3f2eSlogwang 		.field_index = PROTO_FIELD_IPV4,
128*2bfe3f2eSlogwang 		.input_index = PROTO_INPUT_IPV4,
129*2bfe3f2eSlogwang 		.offset = sizeof(struct ether_hdr) +
130*2bfe3f2eSlogwang 			offsetof(struct ipv4_hdr, next_proto_id),
131*2bfe3f2eSlogwang 	},
132*2bfe3f2eSlogwang 	/* next input field (IPv4 source address) - 4 consecutive bytes. */
133*2bfe3f2eSlogwang 	{
134*2bfe3f2eSlogwang 		/* rte_flow uses a bit mask for IPv4 addresses */
135*2bfe3f2eSlogwang 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
136*2bfe3f2eSlogwang 		.size = sizeof(uint32_t),
137*2bfe3f2eSlogwang 		.field_index = SRC_FIELD_IPV4,
138*2bfe3f2eSlogwang 		.input_index = SRC_INPUT_IPV4,
139*2bfe3f2eSlogwang 		.offset = sizeof(struct ether_hdr) +
140*2bfe3f2eSlogwang 			offsetof(struct ipv4_hdr, src_addr),
141*2bfe3f2eSlogwang 	},
142*2bfe3f2eSlogwang 	/* next input field (IPv4 destination address) - 4 consecutive bytes. */
143*2bfe3f2eSlogwang 	{
144*2bfe3f2eSlogwang 		/* rte_flow uses a bit mask for IPv4 addresses */
145*2bfe3f2eSlogwang 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
146*2bfe3f2eSlogwang 		.size = sizeof(uint32_t),
147*2bfe3f2eSlogwang 		.field_index = DST_FIELD_IPV4,
148*2bfe3f2eSlogwang 		.input_index = DST_INPUT_IPV4,
149*2bfe3f2eSlogwang 		.offset = sizeof(struct ether_hdr) +
150*2bfe3f2eSlogwang 			offsetof(struct ipv4_hdr, dst_addr),
151*2bfe3f2eSlogwang 	},
152*2bfe3f2eSlogwang 	/*
153*2bfe3f2eSlogwang 	 * Next 2 fields (src & dst ports) form 4 consecutive bytes.
154*2bfe3f2eSlogwang 	 * They share the same input index.
155*2bfe3f2eSlogwang 	 */
156*2bfe3f2eSlogwang 	{
157*2bfe3f2eSlogwang 		/* rte_flow uses a bit mask for protocol ports */
158*2bfe3f2eSlogwang 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
159*2bfe3f2eSlogwang 		.size = sizeof(uint16_t),
160*2bfe3f2eSlogwang 		.field_index = SRCP_FIELD_IPV4,
161*2bfe3f2eSlogwang 		.input_index = SRCP_DESTP_INPUT_IPV4,
162*2bfe3f2eSlogwang 		.offset = sizeof(struct ether_hdr) +
163*2bfe3f2eSlogwang 			sizeof(struct ipv4_hdr) +
164*2bfe3f2eSlogwang 			offsetof(struct tcp_hdr, src_port),
165*2bfe3f2eSlogwang 	},
166*2bfe3f2eSlogwang 	{
167*2bfe3f2eSlogwang 		/* rte_flow uses a bit mask for protocol ports */
168*2bfe3f2eSlogwang 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
169*2bfe3f2eSlogwang 		.size = sizeof(uint16_t),
170*2bfe3f2eSlogwang 		.field_index = DSTP_FIELD_IPV4,
171*2bfe3f2eSlogwang 		.input_index = SRCP_DESTP_INPUT_IPV4,
172*2bfe3f2eSlogwang 		.offset = sizeof(struct ether_hdr) +
173*2bfe3f2eSlogwang 			sizeof(struct ipv4_hdr) +
174*2bfe3f2eSlogwang 			offsetof(struct tcp_hdr, dst_port),
175*2bfe3f2eSlogwang 	},
176*2bfe3f2eSlogwang };
177*2bfe3f2eSlogwang 
178*2bfe3f2eSlogwang /* flow classify data */
179*2bfe3f2eSlogwang static int num_classify_rules;
180*2bfe3f2eSlogwang static struct rte_flow_classify_rule *rules[MAX_NUM_CLASSIFY];
181*2bfe3f2eSlogwang static struct rte_flow_classify_ipv4_5tuple_stats ntuple_stats;
182*2bfe3f2eSlogwang static struct rte_flow_classify_stats classify_stats = {
183*2bfe3f2eSlogwang 		.stats = (void **)&ntuple_stats
184*2bfe3f2eSlogwang };
185*2bfe3f2eSlogwang 
186*2bfe3f2eSlogwang /* parameters for rte_flow_classify_validate and
187*2bfe3f2eSlogwang  * rte_flow_classify_table_entry_add functions
188*2bfe3f2eSlogwang  */
189*2bfe3f2eSlogwang 
190*2bfe3f2eSlogwang static struct rte_flow_item  eth_item = { RTE_FLOW_ITEM_TYPE_ETH,
191*2bfe3f2eSlogwang 	0, 0, 0 };
192*2bfe3f2eSlogwang static struct rte_flow_item  end_item = { RTE_FLOW_ITEM_TYPE_END,
193*2bfe3f2eSlogwang 	0, 0, 0 };
194*2bfe3f2eSlogwang 
195*2bfe3f2eSlogwang /* sample actions:
196*2bfe3f2eSlogwang  * "actions count / end"
197*2bfe3f2eSlogwang  */
198*2bfe3f2eSlogwang static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, 0};
199*2bfe3f2eSlogwang static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
200*2bfe3f2eSlogwang static struct rte_flow_action actions[2];
201*2bfe3f2eSlogwang 
202*2bfe3f2eSlogwang /* sample attributes */
203*2bfe3f2eSlogwang static struct rte_flow_attr attr;
204*2bfe3f2eSlogwang 
205*2bfe3f2eSlogwang /* flow_classify.c: * Based on DPDK skeleton forwarding example. */
206*2bfe3f2eSlogwang 
207*2bfe3f2eSlogwang /*
208*2bfe3f2eSlogwang  * Initializes a given port using global settings and with the RX buffers
209*2bfe3f2eSlogwang  * coming from the mbuf_pool passed as a parameter.
210*2bfe3f2eSlogwang  */
211*2bfe3f2eSlogwang static inline int
212*2bfe3f2eSlogwang port_init(uint8_t port, struct rte_mempool *mbuf_pool)
213*2bfe3f2eSlogwang {
214*2bfe3f2eSlogwang 	struct rte_eth_conf port_conf = port_conf_default;
215*2bfe3f2eSlogwang 	struct ether_addr addr;
216*2bfe3f2eSlogwang 	const uint16_t rx_rings = 1, tx_rings = 1;
217*2bfe3f2eSlogwang 	int retval;
218*2bfe3f2eSlogwang 	uint16_t q;
219*2bfe3f2eSlogwang 
220*2bfe3f2eSlogwang 	if (port >= rte_eth_dev_count())
221*2bfe3f2eSlogwang 		return -1;
222*2bfe3f2eSlogwang 
223*2bfe3f2eSlogwang 	/* Configure the Ethernet device. */
224*2bfe3f2eSlogwang 	retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
225*2bfe3f2eSlogwang 	if (retval != 0)
226*2bfe3f2eSlogwang 		return retval;
227*2bfe3f2eSlogwang 
228*2bfe3f2eSlogwang 	/* Allocate and set up 1 RX queue per Ethernet port. */
229*2bfe3f2eSlogwang 	for (q = 0; q < rx_rings; q++) {
230*2bfe3f2eSlogwang 		retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
231*2bfe3f2eSlogwang 				rte_eth_dev_socket_id(port), NULL, mbuf_pool);
232*2bfe3f2eSlogwang 		if (retval < 0)
233*2bfe3f2eSlogwang 			return retval;
234*2bfe3f2eSlogwang 	}
235*2bfe3f2eSlogwang 
236*2bfe3f2eSlogwang 	/* Allocate and set up 1 TX queue per Ethernet port. */
237*2bfe3f2eSlogwang 	for (q = 0; q < tx_rings; q++) {
238*2bfe3f2eSlogwang 		retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
239*2bfe3f2eSlogwang 				rte_eth_dev_socket_id(port), NULL);
240*2bfe3f2eSlogwang 		if (retval < 0)
241*2bfe3f2eSlogwang 			return retval;
242*2bfe3f2eSlogwang 	}
243*2bfe3f2eSlogwang 
244*2bfe3f2eSlogwang 	/* Start the Ethernet port. */
245*2bfe3f2eSlogwang 	retval = rte_eth_dev_start(port);
246*2bfe3f2eSlogwang 	if (retval < 0)
247*2bfe3f2eSlogwang 		return retval;
248*2bfe3f2eSlogwang 
249*2bfe3f2eSlogwang 	/* Display the port MAC address. */
250*2bfe3f2eSlogwang 	rte_eth_macaddr_get(port, &addr);
251*2bfe3f2eSlogwang 	printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
252*2bfe3f2eSlogwang 			   " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
253*2bfe3f2eSlogwang 			port,
254*2bfe3f2eSlogwang 			addr.addr_bytes[0], addr.addr_bytes[1],
255*2bfe3f2eSlogwang 			addr.addr_bytes[2], addr.addr_bytes[3],
256*2bfe3f2eSlogwang 			addr.addr_bytes[4], addr.addr_bytes[5]);
257*2bfe3f2eSlogwang 
258*2bfe3f2eSlogwang 	/* Enable RX in promiscuous mode for the Ethernet device. */
259*2bfe3f2eSlogwang 	rte_eth_promiscuous_enable(port);
260*2bfe3f2eSlogwang 
261*2bfe3f2eSlogwang 	return 0;
262*2bfe3f2eSlogwang }
263*2bfe3f2eSlogwang 
264*2bfe3f2eSlogwang /*
265*2bfe3f2eSlogwang  * The lcore main. This is the main thread that does the work, reading from
266*2bfe3f2eSlogwang  * an input port classifying the packets and writing to an output port.
267*2bfe3f2eSlogwang  */
268*2bfe3f2eSlogwang static __attribute__((noreturn)) void
269*2bfe3f2eSlogwang lcore_main(struct flow_classifier *cls_app)
270*2bfe3f2eSlogwang {
271*2bfe3f2eSlogwang 	const uint8_t nb_ports = rte_eth_dev_count();
272*2bfe3f2eSlogwang 	uint8_t port;
273*2bfe3f2eSlogwang 	int ret;
274*2bfe3f2eSlogwang 	int i = 0;
275*2bfe3f2eSlogwang 
276*2bfe3f2eSlogwang 	ret = rte_flow_classify_table_entry_delete(cls_app->cls,
277*2bfe3f2eSlogwang 			cls_app->table_id[0], rules[7]);
278*2bfe3f2eSlogwang 	if (ret)
279*2bfe3f2eSlogwang 		printf("table_entry_delete failed [7] %d\n\n", ret);
280*2bfe3f2eSlogwang 	else
281*2bfe3f2eSlogwang 		printf("table_entry_delete succeeded [7]\n\n");
282*2bfe3f2eSlogwang 
283*2bfe3f2eSlogwang 	/*
284*2bfe3f2eSlogwang 	 * Check that the port is on the same NUMA node as the polling thread
285*2bfe3f2eSlogwang 	 * for best performance.
286*2bfe3f2eSlogwang 	 */
287*2bfe3f2eSlogwang 	for (port = 0; port < nb_ports; port++)
288*2bfe3f2eSlogwang 		if (rte_eth_dev_socket_id(port) > 0 &&
289*2bfe3f2eSlogwang 			rte_eth_dev_socket_id(port) != (int)rte_socket_id()) {
290*2bfe3f2eSlogwang 			printf("\n\n");
291*2bfe3f2eSlogwang 			printf("WARNING: port %u is on remote NUMA node\n",
292*2bfe3f2eSlogwang 			       port);
293*2bfe3f2eSlogwang 			printf("to polling thread.\n");
294*2bfe3f2eSlogwang 			printf("Performance will not be optimal.\n");
295*2bfe3f2eSlogwang 
296*2bfe3f2eSlogwang 			printf("\nCore %u forwarding packets. ",
297*2bfe3f2eSlogwang 			       rte_lcore_id());
298*2bfe3f2eSlogwang 			printf("[Ctrl+C to quit]\n");
299*2bfe3f2eSlogwang 		}
300*2bfe3f2eSlogwang 	/* Run until the application is quit or killed. */
301*2bfe3f2eSlogwang 	for (;;) {
302*2bfe3f2eSlogwang 		/*
303*2bfe3f2eSlogwang 		 * Receive packets on a port, classify them and forward them
304*2bfe3f2eSlogwang 		 * on the paired port.
305*2bfe3f2eSlogwang 		 * The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
306*2bfe3f2eSlogwang 		 */
307*2bfe3f2eSlogwang 		for (port = 0; port < nb_ports; port++) {
308*2bfe3f2eSlogwang 			/* Get burst of RX packets, from first port of pair. */
309*2bfe3f2eSlogwang 			struct rte_mbuf *bufs[BURST_SIZE];
310*2bfe3f2eSlogwang 			const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
311*2bfe3f2eSlogwang 					bufs, BURST_SIZE);
312*2bfe3f2eSlogwang 
313*2bfe3f2eSlogwang 			if (unlikely(nb_rx == 0))
314*2bfe3f2eSlogwang 				continue;
315*2bfe3f2eSlogwang 
316*2bfe3f2eSlogwang 			for (i = 0; i < MAX_NUM_CLASSIFY; i++) {
317*2bfe3f2eSlogwang 				if (rules[i]) {
318*2bfe3f2eSlogwang 					ret = rte_flow_classifier_query(
319*2bfe3f2eSlogwang 						cls_app->cls,
320*2bfe3f2eSlogwang 						cls_app->table_id[0],
321*2bfe3f2eSlogwang 						bufs, nb_rx, rules[i],
322*2bfe3f2eSlogwang 						&classify_stats);
323*2bfe3f2eSlogwang 					if (ret)
324*2bfe3f2eSlogwang 						printf(
325*2bfe3f2eSlogwang 							"rule [%d] query failed ret [%d]\n\n",
326*2bfe3f2eSlogwang 							i, ret);
327*2bfe3f2eSlogwang 					else {
328*2bfe3f2eSlogwang 						printf(
329*2bfe3f2eSlogwang 						"rule[%d] count=%"PRIu64"\n",
330*2bfe3f2eSlogwang 						i, ntuple_stats.counter1);
331*2bfe3f2eSlogwang 
332*2bfe3f2eSlogwang 						printf("proto = %d\n",
333*2bfe3f2eSlogwang 						ntuple_stats.ipv4_5tuple.proto);
334*2bfe3f2eSlogwang 					}
335*2bfe3f2eSlogwang 				}
336*2bfe3f2eSlogwang 			}
337*2bfe3f2eSlogwang 
338*2bfe3f2eSlogwang 			/* Send burst of TX packets, to second port of pair. */
339*2bfe3f2eSlogwang 			const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
340*2bfe3f2eSlogwang 					bufs, nb_rx);
341*2bfe3f2eSlogwang 
342*2bfe3f2eSlogwang 			/* Free any unsent packets. */
343*2bfe3f2eSlogwang 			if (unlikely(nb_tx < nb_rx)) {
344*2bfe3f2eSlogwang 				uint16_t buf;
345*2bfe3f2eSlogwang 
346*2bfe3f2eSlogwang 				for (buf = nb_tx; buf < nb_rx; buf++)
347*2bfe3f2eSlogwang 					rte_pktmbuf_free(bufs[buf]);
348*2bfe3f2eSlogwang 			}
349*2bfe3f2eSlogwang 		}
350*2bfe3f2eSlogwang 	}
351*2bfe3f2eSlogwang }
352*2bfe3f2eSlogwang 
353*2bfe3f2eSlogwang /*
354*2bfe3f2eSlogwang  * Parse IPv4 5 tuple rules file, ipv4_rules_file.txt.
355*2bfe3f2eSlogwang  * Expected format:
356*2bfe3f2eSlogwang  * <src_ipv4_addr>'/'<masklen> <space> \
357*2bfe3f2eSlogwang  * <dst_ipv4_addr>'/'<masklen> <space> \
358*2bfe3f2eSlogwang  * <src_port> <space> ":" <src_port_mask> <space> \
359*2bfe3f2eSlogwang  * <dst_port> <space> ":" <dst_port_mask> <space> \
360*2bfe3f2eSlogwang  * <proto>'/'<proto_mask> <space> \
361*2bfe3f2eSlogwang  * <priority>
362*2bfe3f2eSlogwang  */
363*2bfe3f2eSlogwang 
364*2bfe3f2eSlogwang static int
365*2bfe3f2eSlogwang get_cb_field(char **in, uint32_t *fd, int base, unsigned long lim,
366*2bfe3f2eSlogwang 		char dlm)
367*2bfe3f2eSlogwang {
368*2bfe3f2eSlogwang 	unsigned long val;
369*2bfe3f2eSlogwang 	char *end;
370*2bfe3f2eSlogwang 
371*2bfe3f2eSlogwang 	errno = 0;
372*2bfe3f2eSlogwang 	val = strtoul(*in, &end, base);
373*2bfe3f2eSlogwang 	if (errno != 0 || end[0] != dlm || val > lim)
374*2bfe3f2eSlogwang 		return -EINVAL;
375*2bfe3f2eSlogwang 	*fd = (uint32_t)val;
376*2bfe3f2eSlogwang 	*in = end + 1;
377*2bfe3f2eSlogwang 	return 0;
378*2bfe3f2eSlogwang }
379*2bfe3f2eSlogwang 
380*2bfe3f2eSlogwang static int
381*2bfe3f2eSlogwang parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len)
382*2bfe3f2eSlogwang {
383*2bfe3f2eSlogwang 	uint32_t a, b, c, d, m;
384*2bfe3f2eSlogwang 
385*2bfe3f2eSlogwang 	if (get_cb_field(&in, &a, 0, UINT8_MAX, '.'))
386*2bfe3f2eSlogwang 		return -EINVAL;
387*2bfe3f2eSlogwang 	if (get_cb_field(&in, &b, 0, UINT8_MAX, '.'))
388*2bfe3f2eSlogwang 		return -EINVAL;
389*2bfe3f2eSlogwang 	if (get_cb_field(&in, &c, 0, UINT8_MAX, '.'))
390*2bfe3f2eSlogwang 		return -EINVAL;
391*2bfe3f2eSlogwang 	if (get_cb_field(&in, &d, 0, UINT8_MAX, '/'))
392*2bfe3f2eSlogwang 		return -EINVAL;
393*2bfe3f2eSlogwang 	if (get_cb_field(&in, &m, 0, sizeof(uint32_t) * CHAR_BIT, 0))
394*2bfe3f2eSlogwang 		return -EINVAL;
395*2bfe3f2eSlogwang 
396*2bfe3f2eSlogwang 	addr[0] = IPv4(a, b, c, d);
397*2bfe3f2eSlogwang 	mask_len[0] = m;
398*2bfe3f2eSlogwang 	return 0;
399*2bfe3f2eSlogwang }
400*2bfe3f2eSlogwang 
401*2bfe3f2eSlogwang static int
402*2bfe3f2eSlogwang parse_ipv4_5tuple_rule(char *str, struct rte_eth_ntuple_filter *ntuple_filter)
403*2bfe3f2eSlogwang {
404*2bfe3f2eSlogwang 	int i, ret;
405*2bfe3f2eSlogwang 	char *s, *sp, *in[CB_FLD_NUM];
406*2bfe3f2eSlogwang 	static const char *dlm = " \t\n";
407*2bfe3f2eSlogwang 	int dim = CB_FLD_NUM;
408*2bfe3f2eSlogwang 	uint32_t temp;
409*2bfe3f2eSlogwang 
410*2bfe3f2eSlogwang 	s = str;
411*2bfe3f2eSlogwang 	for (i = 0; i != dim; i++, s = NULL) {
412*2bfe3f2eSlogwang 		in[i] = strtok_r(s, dlm, &sp);
413*2bfe3f2eSlogwang 		if (in[i] == NULL)
414*2bfe3f2eSlogwang 			return -EINVAL;
415*2bfe3f2eSlogwang 	}
416*2bfe3f2eSlogwang 
417*2bfe3f2eSlogwang 	ret = parse_ipv4_net(in[CB_FLD_SRC_ADDR],
418*2bfe3f2eSlogwang 			&ntuple_filter->src_ip,
419*2bfe3f2eSlogwang 			&ntuple_filter->src_ip_mask);
420*2bfe3f2eSlogwang 	if (ret != 0) {
421*2bfe3f2eSlogwang 		flow_classify_log("failed to read source address/mask: %s\n",
422*2bfe3f2eSlogwang 			in[CB_FLD_SRC_ADDR]);
423*2bfe3f2eSlogwang 		return ret;
424*2bfe3f2eSlogwang 	}
425*2bfe3f2eSlogwang 
426*2bfe3f2eSlogwang 	ret = parse_ipv4_net(in[CB_FLD_DST_ADDR],
427*2bfe3f2eSlogwang 			&ntuple_filter->dst_ip,
428*2bfe3f2eSlogwang 			&ntuple_filter->dst_ip_mask);
429*2bfe3f2eSlogwang 	if (ret != 0) {
430*2bfe3f2eSlogwang 		flow_classify_log("failed to read source address/mask: %s\n",
431*2bfe3f2eSlogwang 			in[CB_FLD_DST_ADDR]);
432*2bfe3f2eSlogwang 		return ret;
433*2bfe3f2eSlogwang 	}
434*2bfe3f2eSlogwang 
435*2bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_SRC_PORT], &temp, 0, UINT16_MAX, 0))
436*2bfe3f2eSlogwang 		return -EINVAL;
437*2bfe3f2eSlogwang 	ntuple_filter->src_port = (uint16_t)temp;
438*2bfe3f2eSlogwang 
439*2bfe3f2eSlogwang 	if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
440*2bfe3f2eSlogwang 			sizeof(cb_port_delim)) != 0)
441*2bfe3f2eSlogwang 		return -EINVAL;
442*2bfe3f2eSlogwang 
443*2bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_SRC_PORT_MASK], &temp, 0, UINT16_MAX, 0))
444*2bfe3f2eSlogwang 		return -EINVAL;
445*2bfe3f2eSlogwang 	ntuple_filter->src_port_mask = (uint16_t)temp;
446*2bfe3f2eSlogwang 
447*2bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_DST_PORT], &temp, 0, UINT16_MAX, 0))
448*2bfe3f2eSlogwang 		return -EINVAL;
449*2bfe3f2eSlogwang 	ntuple_filter->dst_port = (uint16_t)temp;
450*2bfe3f2eSlogwang 
451*2bfe3f2eSlogwang 	if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
452*2bfe3f2eSlogwang 			sizeof(cb_port_delim)) != 0)
453*2bfe3f2eSlogwang 		return -EINVAL;
454*2bfe3f2eSlogwang 
455*2bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_DST_PORT_MASK], &temp, 0, UINT16_MAX, 0))
456*2bfe3f2eSlogwang 		return -EINVAL;
457*2bfe3f2eSlogwang 	ntuple_filter->dst_port_mask = (uint16_t)temp;
458*2bfe3f2eSlogwang 
459*2bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, '/'))
460*2bfe3f2eSlogwang 		return -EINVAL;
461*2bfe3f2eSlogwang 	ntuple_filter->proto = (uint8_t)temp;
462*2bfe3f2eSlogwang 
463*2bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, 0))
464*2bfe3f2eSlogwang 		return -EINVAL;
465*2bfe3f2eSlogwang 	ntuple_filter->proto_mask = (uint8_t)temp;
466*2bfe3f2eSlogwang 
467*2bfe3f2eSlogwang 	if (get_cb_field(&in[CB_FLD_PRIORITY], &temp, 0, UINT16_MAX, 0))
468*2bfe3f2eSlogwang 		return -EINVAL;
469*2bfe3f2eSlogwang 	ntuple_filter->priority = (uint16_t)temp;
470*2bfe3f2eSlogwang 	if (ntuple_filter->priority > FLOW_CLASSIFY_MAX_PRIORITY)
471*2bfe3f2eSlogwang 		ret = -EINVAL;
472*2bfe3f2eSlogwang 
473*2bfe3f2eSlogwang 	return ret;
474*2bfe3f2eSlogwang }
475*2bfe3f2eSlogwang 
476*2bfe3f2eSlogwang /* Bypass comment and empty lines */
477*2bfe3f2eSlogwang static inline int
478*2bfe3f2eSlogwang is_bypass_line(char *buff)
479*2bfe3f2eSlogwang {
480*2bfe3f2eSlogwang 	int i = 0;
481*2bfe3f2eSlogwang 
482*2bfe3f2eSlogwang 	/* comment line */
483*2bfe3f2eSlogwang 	if (buff[0] == COMMENT_LEAD_CHAR)
484*2bfe3f2eSlogwang 		return 1;
485*2bfe3f2eSlogwang 	/* empty line */
486*2bfe3f2eSlogwang 	while (buff[i] != '\0') {
487*2bfe3f2eSlogwang 		if (!isspace(buff[i]))
488*2bfe3f2eSlogwang 			return 0;
489*2bfe3f2eSlogwang 		i++;
490*2bfe3f2eSlogwang 	}
491*2bfe3f2eSlogwang 	return 1;
492*2bfe3f2eSlogwang }
493*2bfe3f2eSlogwang 
494*2bfe3f2eSlogwang static uint32_t
495*2bfe3f2eSlogwang convert_depth_to_bitmask(uint32_t depth_val)
496*2bfe3f2eSlogwang {
497*2bfe3f2eSlogwang 	uint32_t bitmask = 0;
498*2bfe3f2eSlogwang 	int i, j;
499*2bfe3f2eSlogwang 
500*2bfe3f2eSlogwang 	for (i = depth_val, j = 0; i > 0; i--, j++)
501*2bfe3f2eSlogwang 		bitmask |= (1 << (31 - j));
502*2bfe3f2eSlogwang 	return bitmask;
503*2bfe3f2eSlogwang }
504*2bfe3f2eSlogwang 
505*2bfe3f2eSlogwang static int
506*2bfe3f2eSlogwang add_classify_rule(struct rte_eth_ntuple_filter *ntuple_filter,
507*2bfe3f2eSlogwang 		struct flow_classifier *cls_app)
508*2bfe3f2eSlogwang {
509*2bfe3f2eSlogwang 	int ret = -1;
510*2bfe3f2eSlogwang 	int key_found;
511*2bfe3f2eSlogwang 	struct rte_flow_error error;
512*2bfe3f2eSlogwang 	struct rte_flow_item_ipv4 ipv4_spec;
513*2bfe3f2eSlogwang 	struct rte_flow_item_ipv4 ipv4_mask;
514*2bfe3f2eSlogwang 	struct rte_flow_item ipv4_udp_item;
515*2bfe3f2eSlogwang 	struct rte_flow_item ipv4_tcp_item;
516*2bfe3f2eSlogwang 	struct rte_flow_item ipv4_sctp_item;
517*2bfe3f2eSlogwang 	struct rte_flow_item_udp udp_spec;
518*2bfe3f2eSlogwang 	struct rte_flow_item_udp udp_mask;
519*2bfe3f2eSlogwang 	struct rte_flow_item udp_item;
520*2bfe3f2eSlogwang 	struct rte_flow_item_tcp tcp_spec;
521*2bfe3f2eSlogwang 	struct rte_flow_item_tcp tcp_mask;
522*2bfe3f2eSlogwang 	struct rte_flow_item tcp_item;
523*2bfe3f2eSlogwang 	struct rte_flow_item_sctp sctp_spec;
524*2bfe3f2eSlogwang 	struct rte_flow_item_sctp sctp_mask;
525*2bfe3f2eSlogwang 	struct rte_flow_item sctp_item;
526*2bfe3f2eSlogwang 	struct rte_flow_item pattern_ipv4_5tuple[4];
527*2bfe3f2eSlogwang 	struct rte_flow_classify_rule *rule;
528*2bfe3f2eSlogwang 	uint8_t ipv4_proto;
529*2bfe3f2eSlogwang 
530*2bfe3f2eSlogwang 	if (num_classify_rules >= MAX_NUM_CLASSIFY) {
531*2bfe3f2eSlogwang 		printf(
532*2bfe3f2eSlogwang 			"\nINFO:  classify rule capacity %d reached\n",
533*2bfe3f2eSlogwang 			num_classify_rules);
534*2bfe3f2eSlogwang 		return ret;
535*2bfe3f2eSlogwang 	}
536*2bfe3f2eSlogwang 
537*2bfe3f2eSlogwang 	/* set up parameters for validate and add */
538*2bfe3f2eSlogwang 	memset(&ipv4_spec, 0, sizeof(ipv4_spec));
539*2bfe3f2eSlogwang 	ipv4_spec.hdr.next_proto_id = ntuple_filter->proto;
540*2bfe3f2eSlogwang 	ipv4_spec.hdr.src_addr = ntuple_filter->src_ip;
541*2bfe3f2eSlogwang 	ipv4_spec.hdr.dst_addr = ntuple_filter->dst_ip;
542*2bfe3f2eSlogwang 	ipv4_proto = ipv4_spec.hdr.next_proto_id;
543*2bfe3f2eSlogwang 
544*2bfe3f2eSlogwang 	memset(&ipv4_mask, 0, sizeof(ipv4_mask));
545*2bfe3f2eSlogwang 	ipv4_mask.hdr.next_proto_id = ntuple_filter->proto_mask;
546*2bfe3f2eSlogwang 	ipv4_mask.hdr.src_addr = ntuple_filter->src_ip_mask;
547*2bfe3f2eSlogwang 	ipv4_mask.hdr.src_addr =
548*2bfe3f2eSlogwang 		convert_depth_to_bitmask(ipv4_mask.hdr.src_addr);
549*2bfe3f2eSlogwang 	ipv4_mask.hdr.dst_addr = ntuple_filter->dst_ip_mask;
550*2bfe3f2eSlogwang 	ipv4_mask.hdr.dst_addr =
551*2bfe3f2eSlogwang 		convert_depth_to_bitmask(ipv4_mask.hdr.dst_addr);
552*2bfe3f2eSlogwang 
553*2bfe3f2eSlogwang 	switch (ipv4_proto) {
554*2bfe3f2eSlogwang 	case IPPROTO_UDP:
555*2bfe3f2eSlogwang 		ipv4_udp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
556*2bfe3f2eSlogwang 		ipv4_udp_item.spec = &ipv4_spec;
557*2bfe3f2eSlogwang 		ipv4_udp_item.mask = &ipv4_mask;
558*2bfe3f2eSlogwang 		ipv4_udp_item.last = NULL;
559*2bfe3f2eSlogwang 
560*2bfe3f2eSlogwang 		udp_spec.hdr.src_port = ntuple_filter->src_port;
561*2bfe3f2eSlogwang 		udp_spec.hdr.dst_port = ntuple_filter->dst_port;
562*2bfe3f2eSlogwang 		udp_spec.hdr.dgram_len = 0;
563*2bfe3f2eSlogwang 		udp_spec.hdr.dgram_cksum = 0;
564*2bfe3f2eSlogwang 
565*2bfe3f2eSlogwang 		udp_mask.hdr.src_port = ntuple_filter->src_port_mask;
566*2bfe3f2eSlogwang 		udp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
567*2bfe3f2eSlogwang 		udp_mask.hdr.dgram_len = 0;
568*2bfe3f2eSlogwang 		udp_mask.hdr.dgram_cksum = 0;
569*2bfe3f2eSlogwang 
570*2bfe3f2eSlogwang 		udp_item.type = RTE_FLOW_ITEM_TYPE_UDP;
571*2bfe3f2eSlogwang 		udp_item.spec = &udp_spec;
572*2bfe3f2eSlogwang 		udp_item.mask = &udp_mask;
573*2bfe3f2eSlogwang 		udp_item.last = NULL;
574*2bfe3f2eSlogwang 
575*2bfe3f2eSlogwang 		attr.priority = ntuple_filter->priority;
576*2bfe3f2eSlogwang 		pattern_ipv4_5tuple[1] = ipv4_udp_item;
577*2bfe3f2eSlogwang 		pattern_ipv4_5tuple[2] = udp_item;
578*2bfe3f2eSlogwang 		break;
579*2bfe3f2eSlogwang 	case IPPROTO_TCP:
580*2bfe3f2eSlogwang 		ipv4_tcp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
581*2bfe3f2eSlogwang 		ipv4_tcp_item.spec = &ipv4_spec;
582*2bfe3f2eSlogwang 		ipv4_tcp_item.mask = &ipv4_mask;
583*2bfe3f2eSlogwang 		ipv4_tcp_item.last = NULL;
584*2bfe3f2eSlogwang 
585*2bfe3f2eSlogwang 		memset(&tcp_spec, 0, sizeof(tcp_spec));
586*2bfe3f2eSlogwang 		tcp_spec.hdr.src_port = ntuple_filter->src_port;
587*2bfe3f2eSlogwang 		tcp_spec.hdr.dst_port = ntuple_filter->dst_port;
588*2bfe3f2eSlogwang 
589*2bfe3f2eSlogwang 		memset(&tcp_mask, 0, sizeof(tcp_mask));
590*2bfe3f2eSlogwang 		tcp_mask.hdr.src_port = ntuple_filter->src_port_mask;
591*2bfe3f2eSlogwang 		tcp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
592*2bfe3f2eSlogwang 
593*2bfe3f2eSlogwang 		tcp_item.type = RTE_FLOW_ITEM_TYPE_TCP;
594*2bfe3f2eSlogwang 		tcp_item.spec = &tcp_spec;
595*2bfe3f2eSlogwang 		tcp_item.mask = &tcp_mask;
596*2bfe3f2eSlogwang 		tcp_item.last = NULL;
597*2bfe3f2eSlogwang 
598*2bfe3f2eSlogwang 		attr.priority = ntuple_filter->priority;
599*2bfe3f2eSlogwang 		pattern_ipv4_5tuple[1] = ipv4_tcp_item;
600*2bfe3f2eSlogwang 		pattern_ipv4_5tuple[2] = tcp_item;
601*2bfe3f2eSlogwang 		break;
602*2bfe3f2eSlogwang 	case IPPROTO_SCTP:
603*2bfe3f2eSlogwang 		ipv4_sctp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
604*2bfe3f2eSlogwang 		ipv4_sctp_item.spec = &ipv4_spec;
605*2bfe3f2eSlogwang 		ipv4_sctp_item.mask = &ipv4_mask;
606*2bfe3f2eSlogwang 		ipv4_sctp_item.last = NULL;
607*2bfe3f2eSlogwang 
608*2bfe3f2eSlogwang 		sctp_spec.hdr.src_port = ntuple_filter->src_port;
609*2bfe3f2eSlogwang 		sctp_spec.hdr.dst_port = ntuple_filter->dst_port;
610*2bfe3f2eSlogwang 		sctp_spec.hdr.cksum = 0;
611*2bfe3f2eSlogwang 		sctp_spec.hdr.tag = 0;
612*2bfe3f2eSlogwang 
613*2bfe3f2eSlogwang 		sctp_mask.hdr.src_port = ntuple_filter->src_port_mask;
614*2bfe3f2eSlogwang 		sctp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
615*2bfe3f2eSlogwang 		sctp_mask.hdr.cksum = 0;
616*2bfe3f2eSlogwang 		sctp_mask.hdr.tag = 0;
617*2bfe3f2eSlogwang 
618*2bfe3f2eSlogwang 		sctp_item.type = RTE_FLOW_ITEM_TYPE_SCTP;
619*2bfe3f2eSlogwang 		sctp_item.spec = &sctp_spec;
620*2bfe3f2eSlogwang 		sctp_item.mask = &sctp_mask;
621*2bfe3f2eSlogwang 		sctp_item.last = NULL;
622*2bfe3f2eSlogwang 
623*2bfe3f2eSlogwang 		attr.priority = ntuple_filter->priority;
624*2bfe3f2eSlogwang 		pattern_ipv4_5tuple[1] = ipv4_sctp_item;
625*2bfe3f2eSlogwang 		pattern_ipv4_5tuple[2] = sctp_item;
626*2bfe3f2eSlogwang 		break;
627*2bfe3f2eSlogwang 	default:
628*2bfe3f2eSlogwang 		return ret;
629*2bfe3f2eSlogwang 	}
630*2bfe3f2eSlogwang 
631*2bfe3f2eSlogwang 	attr.ingress = 1;
632*2bfe3f2eSlogwang 	pattern_ipv4_5tuple[0] = eth_item;
633*2bfe3f2eSlogwang 	pattern_ipv4_5tuple[3] = end_item;
634*2bfe3f2eSlogwang 	actions[0] = count_action;
635*2bfe3f2eSlogwang 	actions[1] = end_action;
636*2bfe3f2eSlogwang 
637*2bfe3f2eSlogwang 	rule = rte_flow_classify_table_entry_add(
638*2bfe3f2eSlogwang 			cls_app->cls, cls_app->table_id[0], &key_found,
639*2bfe3f2eSlogwang 			&attr, pattern_ipv4_5tuple, actions, &error);
640*2bfe3f2eSlogwang 	if (rule == NULL) {
641*2bfe3f2eSlogwang 		printf("table entry add failed ipv4_proto = %u\n",
642*2bfe3f2eSlogwang 			ipv4_proto);
643*2bfe3f2eSlogwang 		ret = -1;
644*2bfe3f2eSlogwang 		return ret;
645*2bfe3f2eSlogwang 	}
646*2bfe3f2eSlogwang 
647*2bfe3f2eSlogwang 	rules[num_classify_rules] = rule;
648*2bfe3f2eSlogwang 	num_classify_rules++;
649*2bfe3f2eSlogwang 	return 0;
650*2bfe3f2eSlogwang }
651*2bfe3f2eSlogwang 
652*2bfe3f2eSlogwang static int
653*2bfe3f2eSlogwang add_rules(const char *rule_path, struct flow_classifier *cls_app)
654*2bfe3f2eSlogwang {
655*2bfe3f2eSlogwang 	FILE *fh;
656*2bfe3f2eSlogwang 	char buff[LINE_MAX];
657*2bfe3f2eSlogwang 	unsigned int i = 0;
658*2bfe3f2eSlogwang 	unsigned int total_num = 0;
659*2bfe3f2eSlogwang 	struct rte_eth_ntuple_filter ntuple_filter;
660*2bfe3f2eSlogwang 	int ret;
661*2bfe3f2eSlogwang 
662*2bfe3f2eSlogwang 	fh = fopen(rule_path, "rb");
663*2bfe3f2eSlogwang 	if (fh == NULL)
664*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "%s: fopen %s failed\n", __func__,
665*2bfe3f2eSlogwang 			rule_path);
666*2bfe3f2eSlogwang 
667*2bfe3f2eSlogwang 	ret = fseek(fh, 0, SEEK_SET);
668*2bfe3f2eSlogwang 	if (ret)
669*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "%s: fseek %d failed\n", __func__,
670*2bfe3f2eSlogwang 			ret);
671*2bfe3f2eSlogwang 
672*2bfe3f2eSlogwang 	i = 0;
673*2bfe3f2eSlogwang 	while (fgets(buff, LINE_MAX, fh) != NULL) {
674*2bfe3f2eSlogwang 		i++;
675*2bfe3f2eSlogwang 
676*2bfe3f2eSlogwang 		if (is_bypass_line(buff))
677*2bfe3f2eSlogwang 			continue;
678*2bfe3f2eSlogwang 
679*2bfe3f2eSlogwang 		if (total_num >= FLOW_CLASSIFY_MAX_RULE_NUM - 1) {
680*2bfe3f2eSlogwang 			printf("\nINFO: classify rule capacity %d reached\n",
681*2bfe3f2eSlogwang 				total_num);
682*2bfe3f2eSlogwang 			break;
683*2bfe3f2eSlogwang 		}
684*2bfe3f2eSlogwang 
685*2bfe3f2eSlogwang 		if (parse_ipv4_5tuple_rule(buff, &ntuple_filter) != 0)
686*2bfe3f2eSlogwang 			rte_exit(EXIT_FAILURE,
687*2bfe3f2eSlogwang 				"%s Line %u: parse rules error\n",
688*2bfe3f2eSlogwang 				rule_path, i);
689*2bfe3f2eSlogwang 
690*2bfe3f2eSlogwang 		if (add_classify_rule(&ntuple_filter, cls_app) != 0)
691*2bfe3f2eSlogwang 			rte_exit(EXIT_FAILURE, "add rule error\n");
692*2bfe3f2eSlogwang 
693*2bfe3f2eSlogwang 		total_num++;
694*2bfe3f2eSlogwang 	}
695*2bfe3f2eSlogwang 
696*2bfe3f2eSlogwang 	fclose(fh);
697*2bfe3f2eSlogwang 	return 0;
698*2bfe3f2eSlogwang }
699*2bfe3f2eSlogwang 
700*2bfe3f2eSlogwang /* display usage */
701*2bfe3f2eSlogwang static void
702*2bfe3f2eSlogwang print_usage(const char *prgname)
703*2bfe3f2eSlogwang {
704*2bfe3f2eSlogwang 	printf("%s usage:\n", prgname);
705*2bfe3f2eSlogwang 	printf("[EAL options] --  --"OPTION_RULE_IPV4"=FILE: ");
706*2bfe3f2eSlogwang 	printf("specify the ipv4 rules file.\n");
707*2bfe3f2eSlogwang 	printf("Each rule occupies one line in the file.\n");
708*2bfe3f2eSlogwang }
709*2bfe3f2eSlogwang 
710*2bfe3f2eSlogwang /* Parse the argument given in the command line of the application */
711*2bfe3f2eSlogwang static int
712*2bfe3f2eSlogwang parse_args(int argc, char **argv)
713*2bfe3f2eSlogwang {
714*2bfe3f2eSlogwang 	int opt, ret;
715*2bfe3f2eSlogwang 	char **argvopt;
716*2bfe3f2eSlogwang 	int option_index;
717*2bfe3f2eSlogwang 	char *prgname = argv[0];
718*2bfe3f2eSlogwang 	static struct option lgopts[] = {
719*2bfe3f2eSlogwang 		{OPTION_RULE_IPV4, 1, 0, 0},
720*2bfe3f2eSlogwang 		{NULL, 0, 0, 0}
721*2bfe3f2eSlogwang 	};
722*2bfe3f2eSlogwang 
723*2bfe3f2eSlogwang 	argvopt = argv;
724*2bfe3f2eSlogwang 
725*2bfe3f2eSlogwang 	while ((opt = getopt_long(argc, argvopt, "",
726*2bfe3f2eSlogwang 				lgopts, &option_index)) != EOF) {
727*2bfe3f2eSlogwang 
728*2bfe3f2eSlogwang 		switch (opt) {
729*2bfe3f2eSlogwang 		/* long options */
730*2bfe3f2eSlogwang 		case 0:
731*2bfe3f2eSlogwang 			if (!strncmp(lgopts[option_index].name,
732*2bfe3f2eSlogwang 					OPTION_RULE_IPV4,
733*2bfe3f2eSlogwang 					sizeof(OPTION_RULE_IPV4)))
734*2bfe3f2eSlogwang 				parm_config.rule_ipv4_name = optarg;
735*2bfe3f2eSlogwang 			break;
736*2bfe3f2eSlogwang 		default:
737*2bfe3f2eSlogwang 			print_usage(prgname);
738*2bfe3f2eSlogwang 			return -1;
739*2bfe3f2eSlogwang 		}
740*2bfe3f2eSlogwang 	}
741*2bfe3f2eSlogwang 
742*2bfe3f2eSlogwang 	if (optind >= 0)
743*2bfe3f2eSlogwang 		argv[optind-1] = prgname;
744*2bfe3f2eSlogwang 
745*2bfe3f2eSlogwang 	ret = optind-1;
746*2bfe3f2eSlogwang 	optind = 1; /* reset getopt lib */
747*2bfe3f2eSlogwang 	return ret;
748*2bfe3f2eSlogwang }
749*2bfe3f2eSlogwang 
750*2bfe3f2eSlogwang /*
751*2bfe3f2eSlogwang  * The main function, which does initialization and calls the lcore_main
752*2bfe3f2eSlogwang  * function.
753*2bfe3f2eSlogwang  */
754*2bfe3f2eSlogwang int
755*2bfe3f2eSlogwang main(int argc, char *argv[])
756*2bfe3f2eSlogwang {
757*2bfe3f2eSlogwang 	struct rte_mempool *mbuf_pool;
758*2bfe3f2eSlogwang 	uint8_t nb_ports;
759*2bfe3f2eSlogwang 	uint8_t portid;
760*2bfe3f2eSlogwang 	int ret;
761*2bfe3f2eSlogwang 	int socket_id;
762*2bfe3f2eSlogwang 	struct rte_table_acl_params table_acl_params;
763*2bfe3f2eSlogwang 	struct rte_flow_classify_table_params cls_table_params;
764*2bfe3f2eSlogwang 	struct flow_classifier *cls_app;
765*2bfe3f2eSlogwang 	struct rte_flow_classifier_params cls_params;
766*2bfe3f2eSlogwang 	uint32_t size;
767*2bfe3f2eSlogwang 
768*2bfe3f2eSlogwang 	/* Initialize the Environment Abstraction Layer (EAL). */
769*2bfe3f2eSlogwang 	ret = rte_eal_init(argc, argv);
770*2bfe3f2eSlogwang 	if (ret < 0)
771*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
772*2bfe3f2eSlogwang 
773*2bfe3f2eSlogwang 	argc -= ret;
774*2bfe3f2eSlogwang 	argv += ret;
775*2bfe3f2eSlogwang 
776*2bfe3f2eSlogwang 	/* parse application arguments (after the EAL ones) */
777*2bfe3f2eSlogwang 	ret = parse_args(argc, argv);
778*2bfe3f2eSlogwang 	if (ret < 0)
779*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Invalid flow_classify parameters\n");
780*2bfe3f2eSlogwang 
781*2bfe3f2eSlogwang 	/* Check that there is an even number of ports to send/receive on. */
782*2bfe3f2eSlogwang 	nb_ports = rte_eth_dev_count();
783*2bfe3f2eSlogwang 	if (nb_ports < 2 || (nb_ports & 1))
784*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
785*2bfe3f2eSlogwang 
786*2bfe3f2eSlogwang 	/* Creates a new mempool in memory to hold the mbufs. */
787*2bfe3f2eSlogwang 	mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
788*2bfe3f2eSlogwang 		MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
789*2bfe3f2eSlogwang 
790*2bfe3f2eSlogwang 	if (mbuf_pool == NULL)
791*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
792*2bfe3f2eSlogwang 
793*2bfe3f2eSlogwang 	/* Initialize all ports. */
794*2bfe3f2eSlogwang 	for (portid = 0; portid < nb_ports; portid++)
795*2bfe3f2eSlogwang 		if (port_init(portid, mbuf_pool) != 0)
796*2bfe3f2eSlogwang 			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n",
797*2bfe3f2eSlogwang 					portid);
798*2bfe3f2eSlogwang 
799*2bfe3f2eSlogwang 	if (rte_lcore_count() > 1)
800*2bfe3f2eSlogwang 		printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
801*2bfe3f2eSlogwang 
802*2bfe3f2eSlogwang 	socket_id = rte_eth_dev_socket_id(0);
803*2bfe3f2eSlogwang 
804*2bfe3f2eSlogwang 	/* Memory allocation */
805*2bfe3f2eSlogwang 	size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct flow_classifier_acl));
806*2bfe3f2eSlogwang 	cls_app = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
807*2bfe3f2eSlogwang 	if (cls_app == NULL)
808*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Cannot allocate classifier memory\n");
809*2bfe3f2eSlogwang 
810*2bfe3f2eSlogwang 	cls_params.name = "flow_classifier";
811*2bfe3f2eSlogwang 	cls_params.socket_id = socket_id;
812*2bfe3f2eSlogwang 	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
813*2bfe3f2eSlogwang 
814*2bfe3f2eSlogwang 	cls_app->cls = rte_flow_classifier_create(&cls_params);
815*2bfe3f2eSlogwang 	if (cls_app->cls == NULL) {
816*2bfe3f2eSlogwang 		rte_free(cls_app);
817*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Cannot create classifier\n");
818*2bfe3f2eSlogwang 	}
819*2bfe3f2eSlogwang 
820*2bfe3f2eSlogwang 	/* initialise ACL table params */
821*2bfe3f2eSlogwang 	table_acl_params.name = "table_acl_ipv4_5tuple";
822*2bfe3f2eSlogwang 	table_acl_params.n_rules = FLOW_CLASSIFY_MAX_RULE_NUM;
823*2bfe3f2eSlogwang 	table_acl_params.n_rule_fields = RTE_DIM(ipv4_defs);
824*2bfe3f2eSlogwang 	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
825*2bfe3f2eSlogwang 
826*2bfe3f2eSlogwang 	/* initialise table create params */
827*2bfe3f2eSlogwang 	cls_table_params.ops = &rte_table_acl_ops,
828*2bfe3f2eSlogwang 	cls_table_params.arg_create = &table_acl_params,
829*2bfe3f2eSlogwang 
830*2bfe3f2eSlogwang 	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
831*2bfe3f2eSlogwang 			&cls_app->table_id[0]);
832*2bfe3f2eSlogwang 	if (ret) {
833*2bfe3f2eSlogwang 		rte_flow_classifier_free(cls_app->cls);
834*2bfe3f2eSlogwang 		rte_free(cls_app);
835*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Failed to create classifier table\n");
836*2bfe3f2eSlogwang 	}
837*2bfe3f2eSlogwang 
838*2bfe3f2eSlogwang 	/* read file of IPv4 5 tuple rules and initialize parameters
839*2bfe3f2eSlogwang 	 * for rte_flow_classify_validate and rte_flow_classify_table_entry_add
840*2bfe3f2eSlogwang 	 * API's.
841*2bfe3f2eSlogwang 	 */
842*2bfe3f2eSlogwang 	if (add_rules(parm_config.rule_ipv4_name, cls_app)) {
843*2bfe3f2eSlogwang 		rte_flow_classifier_free(cls_app->cls);
844*2bfe3f2eSlogwang 		rte_free(cls_app);
845*2bfe3f2eSlogwang 		rte_exit(EXIT_FAILURE, "Failed to add rules\n");
846*2bfe3f2eSlogwang 	}
847*2bfe3f2eSlogwang 
848*2bfe3f2eSlogwang 	/* Call lcore_main on the master core only. */
849*2bfe3f2eSlogwang 	lcore_main(cls_app);
850*2bfe3f2eSlogwang 
851*2bfe3f2eSlogwang 	return 0;
852*2bfe3f2eSlogwang }
853