xref: /dpdk/app/test/test_flow_classify.c (revision 4efec50c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4 
5 #include <string.h>
6 #include <errno.h>
7 
8 #include "test.h"
9 
10 #include <rte_string_fns.h>
11 #include <rte_mbuf.h>
12 #include <rte_byteorder.h>
13 #include <rte_ip.h>
14 
15 #ifdef RTE_EXEC_ENV_WINDOWS
16 static int
17 test_flow_classify(void)
18 {
19 	printf("flow_classify not supported on Windows, skipping test\n");
20 	return TEST_SKIPPED;
21 }
22 
23 #else
24 
25 #include <rte_acl.h>
26 #include <rte_common.h>
27 #include <rte_table_acl.h>
28 #include <rte_flow.h>
29 #include <rte_flow_classify.h>
30 
31 #include "packet_burst_generator.h"
32 #include "test_flow_classify.h"
33 
34 
35 #define FLOW_CLASSIFY_MAX_RULE_NUM 100
36 #define MAX_PKT_BURST              32
37 #define NB_SOCKETS                 4
38 #define MEMPOOL_CACHE_SIZE         256
39 #define MBUF_SIZE                  512
40 #define NB_MBUF                    512
41 
42 /* test UDP, TCP and SCTP packets */
43 static struct rte_mempool *mbufpool[NB_SOCKETS];
44 static struct rte_mbuf *bufs[MAX_PKT_BURST];
45 
46 static struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
47 	/* first input field - always one byte long. */
48 	{
49 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
50 		.size = sizeof(uint8_t),
51 		.field_index = PROTO_FIELD_IPV4,
52 		.input_index = PROTO_INPUT_IPV4,
53 		.offset = sizeof(struct rte_ether_hdr) +
54 			offsetof(struct rte_ipv4_hdr, next_proto_id),
55 	},
56 	/* next input field (IPv4 source address) - 4 consecutive bytes. */
57 	{
58 		/* rte_flow uses a bit mask for IPv4 addresses */
59 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
60 		.size = sizeof(uint32_t),
61 		.field_index = SRC_FIELD_IPV4,
62 		.input_index = SRC_INPUT_IPV4,
63 		.offset = sizeof(struct rte_ether_hdr) +
64 			offsetof(struct rte_ipv4_hdr, src_addr),
65 	},
66 	/* next input field (IPv4 destination address) - 4 consecutive bytes. */
67 	{
68 		/* rte_flow uses a bit mask for IPv4 addresses */
69 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
70 		.size = sizeof(uint32_t),
71 		.field_index = DST_FIELD_IPV4,
72 		.input_index = DST_INPUT_IPV4,
73 		.offset = sizeof(struct rte_ether_hdr) +
74 			offsetof(struct rte_ipv4_hdr, dst_addr),
75 	},
76 	/*
77 	 * Next 2 fields (src & dst ports) form 4 consecutive bytes.
78 	 * They share the same input index.
79 	 */
80 	{
81 		/* rte_flow uses a bit mask for protocol ports */
82 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
83 		.size = sizeof(uint16_t),
84 		.field_index = SRCP_FIELD_IPV4,
85 		.input_index = SRCP_DESTP_INPUT_IPV4,
86 		.offset = sizeof(struct rte_ether_hdr) +
87 			sizeof(struct rte_ipv4_hdr) +
88 			offsetof(struct rte_tcp_hdr, src_port),
89 	},
90 	{
91 		/* rte_flow uses a bit mask for protocol ports */
92 		.type = RTE_ACL_FIELD_TYPE_BITMASK,
93 		.size = sizeof(uint16_t),
94 		.field_index = DSTP_FIELD_IPV4,
95 		.input_index = SRCP_DESTP_INPUT_IPV4,
96 		.offset = sizeof(struct rte_ether_hdr) +
97 			sizeof(struct rte_ipv4_hdr) +
98 			offsetof(struct rte_tcp_hdr, dst_port),
99 	},
100 };
101 
102 /* parameters for rte_flow_classify_validate and rte_flow_classify_create */
103 
104 /* test UDP pattern:
105  * "eth / ipv4 src spec 2.2.2.3 src mask 255.255.255.00 dst spec 2.2.2.7
106  *  dst mask 255.255.255.00 / udp src is 32 dst is 33 / end"
107  */
108 static struct rte_flow_item_ipv4 ipv4_udp_spec_1 = {
109 	{ { .version_ihl = 0}, 0, 0, 0, 0, 0, IPPROTO_UDP, 0,
110 	  RTE_IPV4(2, 2, 2, 3), RTE_IPV4(2, 2, 2, 7)}
111 };
112 static const struct rte_flow_item_ipv4 ipv4_mask_24 = {
113 	.hdr = {
114 		.next_proto_id = 0xff,
115 		.src_addr = 0xffffff00,
116 		.dst_addr = 0xffffff00,
117 	},
118 };
119 static struct rte_flow_item_udp udp_spec_1 = {
120 	{ 32, 33, 0, 0 }
121 };
122 
123 static struct rte_flow_item  eth_item = { RTE_FLOW_ITEM_TYPE_ETH,
124 	0, 0, 0 };
125 static struct rte_flow_item  eth_item_bad = { -1, 0, 0, 0 };
126 
127 static struct rte_flow_item  ipv4_udp_item_1 = { RTE_FLOW_ITEM_TYPE_IPV4,
128 	&ipv4_udp_spec_1, 0, &ipv4_mask_24};
129 static struct rte_flow_item  ipv4_udp_item_bad = { RTE_FLOW_ITEM_TYPE_IPV4,
130 	NULL, 0, NULL};
131 
132 static struct rte_flow_item  udp_item_1 = { RTE_FLOW_ITEM_TYPE_UDP,
133 	&udp_spec_1, 0, &rte_flow_item_udp_mask};
134 static struct rte_flow_item  udp_item_bad = { RTE_FLOW_ITEM_TYPE_UDP,
135 	NULL, 0, NULL};
136 
137 static struct rte_flow_item  end_item = { RTE_FLOW_ITEM_TYPE_END,
138 	0, 0, 0 };
139 
140 /* test TCP pattern:
141  * "eth / ipv4 src spec 1.2.3.4 src mask 255.255.255.00 dst spec 5.6.7.8
142  *  dst mask 255.255.255.00 / tcp src is 16 dst is 17 / end"
143  */
144 static struct rte_flow_item_ipv4 ipv4_tcp_spec_1 = {
145 	{ { .version_ihl = 0}, 0, 0, 0, 0, 0, IPPROTO_TCP, 0,
146 	  RTE_IPV4(1, 2, 3, 4), RTE_IPV4(5, 6, 7, 8)}
147 };
148 
149 static struct rte_flow_item_tcp tcp_spec_1 = {
150 	{ 16, 17, 0, 0, 0, 0, 0, 0, 0}
151 };
152 
153 static struct rte_flow_item  ipv4_tcp_item_1 = { RTE_FLOW_ITEM_TYPE_IPV4,
154 	&ipv4_tcp_spec_1, 0, &ipv4_mask_24};
155 
156 static struct rte_flow_item  tcp_item_1 = { RTE_FLOW_ITEM_TYPE_TCP,
157 	&tcp_spec_1, 0, &rte_flow_item_tcp_mask};
158 
159 /* test SCTP pattern:
160  * "eth / ipv4 src spec 1.2.3.4 src mask 255.255.255.00 dst spec 5.6.7.8
161  *  dst mask 255.255.255.00 / sctp src is 16 dst is 17/ end"
162  */
163 static struct rte_flow_item_ipv4 ipv4_sctp_spec_1 = {
164 	{ { .version_ihl = 0}, 0, 0, 0, 0, 0, IPPROTO_SCTP, 0,
165 	RTE_IPV4(11, 12, 13, 14), RTE_IPV4(15, 16, 17, 18)}
166 };
167 
168 static struct rte_flow_item_sctp sctp_spec_1 = {
169 	{ 10, 11, 0, 0}
170 };
171 
172 static struct rte_flow_item  ipv4_sctp_item_1 = { RTE_FLOW_ITEM_TYPE_IPV4,
173 	&ipv4_sctp_spec_1, 0, &ipv4_mask_24};
174 
175 static struct rte_flow_item  sctp_item_1 = { RTE_FLOW_ITEM_TYPE_SCTP,
176 	&sctp_spec_1, 0, &rte_flow_item_sctp_mask};
177 
178 
179 /* test actions:
180  * "actions count / end"
181  */
182 static struct rte_flow_query_count count = {
183 	.reset = 1,
184 	.hits_set = 1,
185 	.bytes_set = 1,
186 	.hits = 0,
187 	.bytes = 0,
188 };
189 static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
190 	&count};
191 static struct rte_flow_action count_action_bad = { -1, 0};
192 
193 static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
194 
195 static struct rte_flow_action actions[2];
196 
197 /* test attributes */
198 static struct rte_flow_attr attr;
199 
200 /* test error */
201 static struct rte_flow_error error;
202 
203 /* test pattern */
204 static struct rte_flow_item  pattern[4];
205 
206 /* flow classify data for UDP burst */
207 static struct rte_flow_classify_ipv4_5tuple_stats udp_ntuple_stats;
208 static struct rte_flow_classify_stats udp_classify_stats = {
209 		.stats = (void *)&udp_ntuple_stats
210 };
211 
212 /* flow classify data for TCP burst */
213 static struct rte_flow_classify_ipv4_5tuple_stats tcp_ntuple_stats;
214 static struct rte_flow_classify_stats tcp_classify_stats = {
215 		.stats = (void *)&tcp_ntuple_stats
216 };
217 
218 /* flow classify data for SCTP burst */
219 static struct rte_flow_classify_ipv4_5tuple_stats sctp_ntuple_stats;
220 static struct rte_flow_classify_stats sctp_classify_stats = {
221 		.stats = (void *)&sctp_ntuple_stats
222 };
223 
224 struct flow_classifier_acl *cls;
225 
226 struct flow_classifier_acl {
227 	struct rte_flow_classifier *cls;
228 } __rte_cache_aligned;
229 
230 /*
231  * test functions by passing invalid or
232  * non-workable parameters.
233  */
234 static int
235 test_invalid_parameters(void)
236 {
237 	struct rte_flow_classify_rule *rule;
238 	int ret;
239 
240 	ret = rte_flow_classify_validate(NULL, NULL, NULL, NULL, NULL);
241 	if (!ret) {
242 		printf("Line %i: rte_flow_classify_validate",
243 			__LINE__);
244 		printf(" with NULL param should have failed!\n");
245 		return -1;
246 	}
247 
248 	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
249 			NULL, NULL);
250 	if (rule) {
251 		printf("Line %i: flow_classifier_table_entry_add", __LINE__);
252 		printf(" with NULL param should have failed!\n");
253 		return -1;
254 	}
255 
256 	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
257 	if (!ret) {
258 		printf("Line %i: rte_flow_classify_table_entry_delete",
259 			__LINE__);
260 		printf(" with NULL param should have failed!\n");
261 		return -1;
262 	}
263 
264 	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
265 	if (!ret) {
266 		printf("Line %i: flow_classifier_query", __LINE__);
267 		printf(" with NULL param should have failed!\n");
268 		return -1;
269 	}
270 
271 	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
272 		NULL, &error);
273 	if (rule) {
274 		printf("Line %i: flow_classify_table_entry_add ", __LINE__);
275 		printf("with NULL param should have failed!\n");
276 		return -1;
277 	}
278 
279 	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
280 	if (!ret) {
281 		printf("Line %i: rte_flow_classify_table_entry_delete",
282 			__LINE__);
283 		printf("with NULL param should have failed!\n");
284 		return -1;
285 	}
286 
287 	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
288 	if (!ret) {
289 		printf("Line %i: flow_classifier_query", __LINE__);
290 		printf(" with NULL param should have failed!\n");
291 		return -1;
292 	}
293 	return 0;
294 }
295 
296 static int
297 test_valid_parameters(void)
298 {
299 	struct rte_flow_classify_rule *rule;
300 	int ret;
301 	int key_found;
302 
303 	/*
304 	 * set up parameters for rte_flow_classify_validate,
305 	 * rte_flow_classify_table_entry_add and
306 	 * rte_flow_classify_table_entry_delete
307 	 */
308 
309 	attr.ingress = 1;
310 	attr.priority = 1;
311 	pattern[0] = eth_item;
312 	pattern[1] = ipv4_udp_item_1;
313 	pattern[2] = udp_item_1;
314 	pattern[3] = end_item;
315 	actions[0] = count_action;
316 	actions[1] = end_action;
317 
318 	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
319 			actions, &error);
320 	if (ret) {
321 		printf("Line %i: rte_flow_classify_validate",
322 			__LINE__);
323 		printf(" should not have failed!\n");
324 		return -1;
325 	}
326 	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
327 			actions, &key_found, &error);
328 
329 	if (!rule) {
330 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
331 		printf(" should not have failed!\n");
332 		return -1;
333 	}
334 
335 	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
336 	if (ret) {
337 		printf("Line %i: rte_flow_classify_table_entry_delete",
338 			__LINE__);
339 		printf(" should not have failed!\n");
340 		return -1;
341 	}
342 	return 0;
343 }
344 
345 static int
346 test_invalid_patterns(void)
347 {
348 	struct rte_flow_classify_rule *rule;
349 	int ret;
350 	int key_found;
351 
352 	/*
353 	 * set up parameters for rte_flow_classify_validate,
354 	 * rte_flow_classify_table_entry_add and
355 	 * rte_flow_classify_table_entry_delete
356 	 */
357 
358 	attr.ingress = 1;
359 	attr.priority = 1;
360 	pattern[0] = eth_item_bad;
361 	pattern[1] = ipv4_udp_item_1;
362 	pattern[2] = udp_item_1;
363 	pattern[3] = end_item;
364 	actions[0] = count_action;
365 	actions[1] = end_action;
366 
367 	pattern[0] = eth_item;
368 	pattern[1] = ipv4_udp_item_bad;
369 
370 	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
371 			actions, &error);
372 	if (!ret) {
373 		printf("Line %i: rte_flow_classify_validate", __LINE__);
374 		printf(" should have failed!\n");
375 		return -1;
376 	}
377 
378 	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
379 			actions, &key_found, &error);
380 	if (rule) {
381 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
382 		printf(" should have failed!\n");
383 		return -1;
384 	}
385 
386 	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
387 	if (!ret) {
388 		printf("Line %i: rte_flow_classify_table_entry_delete",
389 			__LINE__);
390 		printf(" should have failed!\n");
391 		return -1;
392 	}
393 
394 	pattern[1] = ipv4_udp_item_1;
395 	pattern[2] = udp_item_bad;
396 	pattern[3] = end_item;
397 
398 	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
399 			actions, &error);
400 	if (!ret) {
401 		printf("Line %i: rte_flow_classify_validate", __LINE__);
402 		printf(" should have failed!\n");
403 		return -1;
404 	}
405 
406 	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
407 			actions, &key_found, &error);
408 	if (rule) {
409 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
410 		printf(" should have failed!\n");
411 		return -1;
412 	}
413 
414 	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
415 	if (!ret) {
416 		printf("Line %i: rte_flow_classify_table_entry_delete",
417 			__LINE__);
418 		printf(" should have failed!\n");
419 		return -1;
420 	}
421 	return 0;
422 }
423 
424 static int
425 test_invalid_actions(void)
426 {
427 	struct rte_flow_classify_rule *rule;
428 	int ret;
429 	int key_found;
430 
431 	/*
432 	 * set up parameters for rte_flow_classify_validate,
433 	 * rte_flow_classify_table_entry_add and
434 	 * rte_flow_classify_table_entry_delete
435 	 */
436 
437 	attr.ingress = 1;
438 	attr.priority = 1;
439 	pattern[0] = eth_item;
440 	pattern[1] = ipv4_udp_item_1;
441 	pattern[2] = udp_item_1;
442 	pattern[3] = end_item;
443 	actions[0] = count_action_bad;
444 	actions[1] = end_action;
445 
446 	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
447 			actions, &error);
448 	if (!ret) {
449 		printf("Line %i: rte_flow_classify_validate", __LINE__);
450 		printf(" should have failed!\n");
451 		return -1;
452 	}
453 
454 	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
455 			actions, &key_found, &error);
456 	if (rule) {
457 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
458 		printf(" should have failed!\n");
459 		return -1;
460 	}
461 
462 	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
463 	if (!ret) {
464 		printf("Line %i: rte_flow_classify_table_entry_delete",
465 			__LINE__);
466 		printf(" should have failed!\n");
467 		return -1;
468 	}
469 
470 	return 0;
471 }
472 
473 static int
474 init_ipv4_udp_traffic(struct rte_mempool *mp,
475 	     struct rte_mbuf **pkts_burst, uint32_t burst_size)
476 {
477 	struct rte_ether_hdr pkt_eth_hdr;
478 	struct rte_ipv4_hdr pkt_ipv4_hdr;
479 	struct rte_udp_hdr pkt_udp_hdr;
480 	uint32_t src_addr = IPV4_ADDR(2, 2, 2, 3);
481 	uint32_t dst_addr = IPV4_ADDR(2, 2, 2, 7);
482 	uint16_t src_port = 32;
483 	uint16_t dst_port = 33;
484 	uint16_t pktlen;
485 
486 	static uint8_t src_mac[] = { 0x00, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
487 	static uint8_t dst_mac[] = { 0x00, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
488 
489 	printf("Set up IPv4 UDP traffic\n");
490 	initialize_eth_header(&pkt_eth_hdr,
491 		(struct rte_ether_addr *)src_mac,
492 		(struct rte_ether_addr *)dst_mac, RTE_ETHER_TYPE_IPV4, 0, 0);
493 	pktlen = (uint16_t)(sizeof(struct rte_ether_hdr));
494 	printf("ETH  pktlen %u\n", pktlen);
495 
496 	pktlen = initialize_ipv4_header(&pkt_ipv4_hdr, src_addr, dst_addr,
497 					pktlen);
498 	printf("ETH + IPv4 pktlen %u\n", pktlen);
499 
500 	pktlen = initialize_udp_header(&pkt_udp_hdr, src_port, dst_port,
501 					pktlen);
502 	printf("ETH + IPv4 + UDP pktlen %u\n\n", pktlen);
503 
504 	return generate_packet_burst(mp, pkts_burst, &pkt_eth_hdr,
505 				     0, &pkt_ipv4_hdr, 1,
506 				     &pkt_udp_hdr, burst_size,
507 				     PACKET_BURST_GEN_PKT_LEN, 1);
508 }
509 
510 static int
511 init_ipv4_tcp_traffic(struct rte_mempool *mp,
512 	     struct rte_mbuf **pkts_burst, uint32_t burst_size)
513 {
514 	struct rte_ether_hdr pkt_eth_hdr;
515 	struct rte_ipv4_hdr pkt_ipv4_hdr;
516 	struct rte_tcp_hdr pkt_tcp_hdr;
517 	uint32_t src_addr = IPV4_ADDR(1, 2, 3, 4);
518 	uint32_t dst_addr = IPV4_ADDR(5, 6, 7, 8);
519 	uint16_t src_port = 16;
520 	uint16_t dst_port = 17;
521 	uint16_t pktlen;
522 
523 	static uint8_t src_mac[] = { 0x00, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
524 	static uint8_t dst_mac[] = { 0x00, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
525 
526 	printf("Set up IPv4 TCP traffic\n");
527 	initialize_eth_header(&pkt_eth_hdr,
528 		(struct rte_ether_addr *)src_mac,
529 		(struct rte_ether_addr *)dst_mac, RTE_ETHER_TYPE_IPV4, 0, 0);
530 	pktlen = (uint16_t)(sizeof(struct rte_ether_hdr));
531 	printf("ETH  pktlen %u\n", pktlen);
532 
533 	pktlen = initialize_ipv4_header_proto(&pkt_ipv4_hdr, src_addr,
534 					dst_addr, pktlen, IPPROTO_TCP);
535 	printf("ETH + IPv4 pktlen %u\n", pktlen);
536 
537 	pktlen = initialize_tcp_header(&pkt_tcp_hdr, src_port, dst_port,
538 					pktlen);
539 	printf("ETH + IPv4 + TCP pktlen %u\n\n", pktlen);
540 
541 	return generate_packet_burst_proto(mp, pkts_burst, &pkt_eth_hdr,
542 					0, &pkt_ipv4_hdr, 1, IPPROTO_TCP,
543 					&pkt_tcp_hdr, burst_size,
544 					PACKET_BURST_GEN_PKT_LEN, 1);
545 }
546 
547 static int
548 init_ipv4_sctp_traffic(struct rte_mempool *mp,
549 	     struct rte_mbuf **pkts_burst, uint32_t burst_size)
550 {
551 	struct rte_ether_hdr pkt_eth_hdr;
552 	struct rte_ipv4_hdr pkt_ipv4_hdr;
553 	struct rte_sctp_hdr pkt_sctp_hdr;
554 	uint32_t src_addr = IPV4_ADDR(11, 12, 13, 14);
555 	uint32_t dst_addr = IPV4_ADDR(15, 16, 17, 18);
556 	uint16_t src_port = 10;
557 	uint16_t dst_port = 11;
558 	uint16_t pktlen;
559 
560 	static uint8_t src_mac[] = { 0x00, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
561 	static uint8_t dst_mac[] = { 0x00, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
562 
563 	printf("Set up IPv4 SCTP traffic\n");
564 	initialize_eth_header(&pkt_eth_hdr,
565 		(struct rte_ether_addr *)src_mac,
566 		(struct rte_ether_addr *)dst_mac, RTE_ETHER_TYPE_IPV4, 0, 0);
567 	pktlen = (uint16_t)(sizeof(struct rte_ether_hdr));
568 	printf("ETH  pktlen %u\n", pktlen);
569 
570 	pktlen = initialize_ipv4_header_proto(&pkt_ipv4_hdr, src_addr,
571 					dst_addr, pktlen, IPPROTO_SCTP);
572 	printf("ETH + IPv4 pktlen %u\n", pktlen);
573 
574 	pktlen = initialize_sctp_header(&pkt_sctp_hdr, src_port, dst_port,
575 					pktlen);
576 	printf("ETH + IPv4 + SCTP pktlen %u\n\n", pktlen);
577 
578 	return generate_packet_burst_proto(mp, pkts_burst, &pkt_eth_hdr,
579 					0, &pkt_ipv4_hdr, 1, IPPROTO_SCTP,
580 					&pkt_sctp_hdr, burst_size,
581 					PACKET_BURST_GEN_PKT_LEN, 1);
582 }
583 
584 static int
585 init_mbufpool(void)
586 {
587 	int socketid;
588 	int ret = 0;
589 	unsigned int lcore_id;
590 	char s[64];
591 
592 	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
593 		if (rte_lcore_is_enabled(lcore_id) == 0)
594 			continue;
595 
596 		socketid = rte_lcore_to_socket_id(lcore_id);
597 		if (socketid >= NB_SOCKETS) {
598 			printf(
599 				"Socket %d of lcore %u is out of range %d\n",
600 				socketid, lcore_id, NB_SOCKETS);
601 			ret = -1;
602 			break;
603 		}
604 		if (mbufpool[socketid] == NULL) {
605 			snprintf(s, sizeof(s), "mbuf_pool_%d", socketid);
606 			mbufpool[socketid] =
607 				rte_pktmbuf_pool_create(s, NB_MBUF,
608 					MEMPOOL_CACHE_SIZE, 0, MBUF_SIZE,
609 					socketid);
610 			if (mbufpool[socketid]) {
611 				printf("Allocated mbuf pool on socket %d\n",
612 					socketid);
613 			} else {
614 				printf("Cannot init mbuf pool on socket %d\n",
615 					socketid);
616 				ret = -ENOMEM;
617 				break;
618 			}
619 		}
620 	}
621 	return ret;
622 }
623 
624 static int
625 test_query_udp(void)
626 {
627 	struct rte_flow_error error;
628 	struct rte_flow_classify_rule *rule;
629 	int ret;
630 	int i;
631 	int key_found;
632 
633 	ret = init_ipv4_udp_traffic(mbufpool[0], bufs, MAX_PKT_BURST);
634 	if (ret != MAX_PKT_BURST) {
635 		printf("Line %i: init_udp_ipv4_traffic has failed!\n",
636 				__LINE__);
637 		return -1;
638 	}
639 
640 	for (i = 0; i < MAX_PKT_BURST; i++)
641 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
642 
643 	/*
644 	 * set up parameters for rte_flow_classify_validate,
645 	 * rte_flow_classify_table_entry_add and
646 	 * rte_flow_classify_table_entry_delete
647 	 */
648 
649 	attr.ingress = 1;
650 	attr.priority = 1;
651 	pattern[0] = eth_item;
652 	pattern[1] = ipv4_udp_item_1;
653 	pattern[2] = udp_item_1;
654 	pattern[3] = end_item;
655 	actions[0] = count_action;
656 	actions[1] = end_action;
657 
658 	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
659 			actions, &error);
660 	if (ret) {
661 		printf("Line %i: rte_flow_classify_validate", __LINE__);
662 		printf(" should not have failed!\n");
663 		return -1;
664 	}
665 
666 	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
667 			actions, &key_found, &error);
668 	if (!rule) {
669 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
670 		printf(" should not have failed!\n");
671 		return -1;
672 	}
673 
674 	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
675 			rule, &udp_classify_stats);
676 	if (ret) {
677 		printf("Line %i: flow_classifier_query", __LINE__);
678 		printf(" should not have failed!\n");
679 		return -1;
680 	}
681 
682 	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
683 	if (ret) {
684 		printf("Line %i: rte_flow_classify_table_entry_delete",
685 			__LINE__);
686 		printf(" should not have failed!\n");
687 		return -1;
688 	}
689 	return 0;
690 }
691 
692 static int
693 test_query_tcp(void)
694 {
695 	struct rte_flow_classify_rule *rule;
696 	int ret;
697 	int i;
698 	int key_found;
699 
700 	ret = init_ipv4_tcp_traffic(mbufpool[0], bufs, MAX_PKT_BURST);
701 	if (ret != MAX_PKT_BURST) {
702 		printf("Line %i: init_ipv4_tcp_traffic has failed!\n",
703 				__LINE__);
704 		return -1;
705 	}
706 
707 	for (i = 0; i < MAX_PKT_BURST; i++)
708 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
709 
710 	/*
711 	 * set up parameters for rte_flow_classify_validate,
712 	 * rte_flow_classify_table_entry_add and
713 	 * rte_flow_classify_table_entry_delete
714 	 */
715 
716 	attr.ingress = 1;
717 	attr.priority = 1;
718 	pattern[0] = eth_item;
719 	pattern[1] = ipv4_tcp_item_1;
720 	pattern[2] = tcp_item_1;
721 	pattern[3] = end_item;
722 	actions[0] = count_action;
723 	actions[1] = end_action;
724 
725 	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
726 			actions, &error);
727 	if (ret) {
728 		printf("Line %i: flow_classifier_query", __LINE__);
729 		printf(" should not have failed!\n");
730 		return -1;
731 	}
732 
733 	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
734 			actions, &key_found, &error);
735 	if (!rule) {
736 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
737 		printf(" should not have failed!\n");
738 		return -1;
739 	}
740 
741 	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
742 			rule, &tcp_classify_stats);
743 	if (ret) {
744 		printf("Line %i: flow_classifier_query", __LINE__);
745 		printf(" should not have failed!\n");
746 		return -1;
747 	}
748 
749 	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
750 	if (ret) {
751 		printf("Line %i: rte_flow_classify_table_entry_delete",
752 			__LINE__);
753 		printf(" should not have failed!\n");
754 		return -1;
755 	}
756 	return 0;
757 }
758 
759 static int
760 test_query_sctp(void)
761 {
762 	struct rte_flow_classify_rule *rule;
763 	int ret;
764 	int i;
765 	int key_found;
766 
767 	ret = init_ipv4_sctp_traffic(mbufpool[0], bufs, MAX_PKT_BURST);
768 	if (ret != MAX_PKT_BURST) {
769 		printf("Line %i: init_ipv4_tcp_traffic has failed!\n",
770 			__LINE__);
771 		return -1;
772 	}
773 
774 	for (i = 0; i < MAX_PKT_BURST; i++)
775 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
776 
777 	/*
778 	 * set up parameters rte_flow_classify_validate,
779 	 * rte_flow_classify_table_entry_add and
780 	 * rte_flow_classify_table_entry_delete
781 	 */
782 
783 	attr.ingress = 1;
784 	attr.priority = 1;
785 	pattern[0] = eth_item;
786 	pattern[1] = ipv4_sctp_item_1;
787 	pattern[2] = sctp_item_1;
788 	pattern[3] = end_item;
789 	actions[0] = count_action;
790 	actions[1] = end_action;
791 
792 	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
793 			actions, &error);
794 	if (ret) {
795 		printf("Line %i: flow_classifier_query", __LINE__);
796 		printf(" should not have failed!\n");
797 		return -1;
798 	}
799 
800 	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
801 			actions, &key_found, &error);
802 	if (!rule) {
803 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
804 		printf(" should not have failed!\n");
805 		return -1;
806 	}
807 
808 	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
809 			rule, &sctp_classify_stats);
810 	if (ret) {
811 		printf("Line %i: flow_classifier_query", __LINE__);
812 		printf(" should not have failed!\n");
813 		return -1;
814 	}
815 
816 	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
817 	if (ret) {
818 		printf("Line %i: rte_flow_classify_table_entry_delete",
819 			__LINE__);
820 		printf(" should not have failed!\n");
821 		return -1;
822 	}
823 	return 0;
824 }
825 
826 static int
827 test_flow_classify(void)
828 {
829 	struct rte_table_acl_params table_acl_params;
830 	struct rte_flow_classify_table_params cls_table_params;
831 	struct rte_flow_classifier_params cls_params;
832 	int ret;
833 	uint32_t size;
834 
835 	/* Memory allocation */
836 	size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct flow_classifier_acl));
837 	cls = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
838 
839 	cls_params.name = "flow_classifier";
840 	cls_params.socket_id = 0;
841 	cls->cls = rte_flow_classifier_create(&cls_params);
842 	if (cls->cls == NULL) {
843 		printf("Line %i: flow classifier create has failed!\n",
844 		       __LINE__);
845 		rte_free(cls);
846 		return TEST_FAILED;
847 	}
848 
849 	/* initialise ACL table params */
850 	table_acl_params.n_rule_fields = RTE_DIM(ipv4_defs);
851 	table_acl_params.name = "table_acl_ipv4_5tuple";
852 	table_acl_params.n_rules = FLOW_CLASSIFY_MAX_RULE_NUM;
853 	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
854 
855 	/* initialise table create params */
856 	cls_table_params.ops = &rte_table_acl_ops;
857 	cls_table_params.arg_create = &table_acl_params;
858 	cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
859 
860 	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params);
861 	if (ret) {
862 		printf("Line %i: f_create has failed!\n", __LINE__);
863 		rte_flow_classifier_free(cls->cls);
864 		rte_free(cls);
865 		return TEST_FAILED;
866 	}
867 	printf("Created table_acl for for IPv4 five tuple packets\n");
868 
869 	ret = init_mbufpool();
870 	if (ret) {
871 		printf("Line %i: init_mbufpool has failed!\n", __LINE__);
872 		return TEST_FAILED;
873 	}
874 
875 	if (test_invalid_parameters() < 0)
876 		return TEST_FAILED;
877 	if (test_valid_parameters() < 0)
878 		return TEST_FAILED;
879 	if (test_invalid_patterns() < 0)
880 		return TEST_FAILED;
881 	if (test_invalid_actions() < 0)
882 		return TEST_FAILED;
883 	if (test_query_udp() < 0)
884 		return TEST_FAILED;
885 	if (test_query_tcp() < 0)
886 		return TEST_FAILED;
887 	if (test_query_sctp() < 0)
888 		return TEST_FAILED;
889 
890 	return TEST_SUCCESS;
891 }
892 
893 #endif /* !RTE_EXEC_ENV_WINDOWS */
894 
895 REGISTER_TEST_COMMAND(flow_classify_autotest, test_flow_classify);
896