xref: /dpdk/app/test/test_acl.c (revision cf435a07)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <string.h>
35 #include <errno.h>
36 
37 #include "test.h"
38 
39 #include <rte_string_fns.h>
40 #include <rte_mbuf.h>
41 #include <rte_byteorder.h>
42 #include <rte_ip.h>
43 #include <rte_acl.h>
44 #include <rte_common.h>
45 
46 #include "test_acl.h"
47 
48 #define	BIT_SIZEOF(x) (sizeof(x) * CHAR_BIT)
49 
50 #define LEN RTE_ACL_MAX_CATEGORIES
51 
52 RTE_ACL_RULE_DEF(acl_ipv4vlan_rule, RTE_ACL_IPV4VLAN_NUM_FIELDS);
53 
54 struct rte_acl_param acl_param = {
55 	.name = "acl_ctx",
56 	.socket_id = SOCKET_ID_ANY,
57 	.rule_size = RTE_ACL_IPV4VLAN_RULE_SZ,
58 	.max_rule_num = 0x30000,
59 };
60 
61 struct rte_acl_ipv4vlan_rule acl_rule = {
62 		.data = { .priority = 1, .category_mask = 0xff },
63 		.src_port_low = 0,
64 		.src_port_high = UINT16_MAX,
65 		.dst_port_low = 0,
66 		.dst_port_high = UINT16_MAX,
67 };
68 
69 const uint32_t ipv4_7tuple_layout[RTE_ACL_IPV4VLAN_NUM] = {
70 	offsetof(struct ipv4_7tuple, proto),
71 	offsetof(struct ipv4_7tuple, vlan),
72 	offsetof(struct ipv4_7tuple, ip_src),
73 	offsetof(struct ipv4_7tuple, ip_dst),
74 	offsetof(struct ipv4_7tuple, port_src),
75 };
76 
77 
78 /* byteswap to cpu or network order */
79 static void
80 bswap_test_data(struct ipv4_7tuple *data, int len, int to_be)
81 {
82 	int i;
83 
84 	for (i = 0; i < len; i++) {
85 
86 		if (to_be) {
87 			/* swap all bytes so that they are in network order */
88 			data[i].ip_dst = rte_cpu_to_be_32(data[i].ip_dst);
89 			data[i].ip_src = rte_cpu_to_be_32(data[i].ip_src);
90 			data[i].port_dst = rte_cpu_to_be_16(data[i].port_dst);
91 			data[i].port_src = rte_cpu_to_be_16(data[i].port_src);
92 			data[i].vlan = rte_cpu_to_be_16(data[i].vlan);
93 			data[i].domain = rte_cpu_to_be_16(data[i].domain);
94 		} else {
95 			data[i].ip_dst = rte_be_to_cpu_32(data[i].ip_dst);
96 			data[i].ip_src = rte_be_to_cpu_32(data[i].ip_src);
97 			data[i].port_dst = rte_be_to_cpu_16(data[i].port_dst);
98 			data[i].port_src = rte_be_to_cpu_16(data[i].port_src);
99 			data[i].vlan = rte_be_to_cpu_16(data[i].vlan);
100 			data[i].domain = rte_be_to_cpu_16(data[i].domain);
101 		}
102 	}
103 }
104 
105 static int
106 acl_ipv4vlan_check_rule(const struct rte_acl_ipv4vlan_rule *rule)
107 {
108 	if (rule->src_port_low > rule->src_port_high ||
109 			rule->dst_port_low > rule->dst_port_high ||
110 			rule->src_mask_len > BIT_SIZEOF(rule->src_addr) ||
111 			rule->dst_mask_len > BIT_SIZEOF(rule->dst_addr))
112 		return -EINVAL;
113 	return 0;
114 }
115 
116 static void
117 acl_ipv4vlan_convert_rule(const struct rte_acl_ipv4vlan_rule *ri,
118 	struct acl_ipv4vlan_rule *ro)
119 {
120 	ro->data = ri->data;
121 
122 	ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].value.u8 = ri->proto;
123 	ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].value.u16 = ri->vlan;
124 	ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].value.u16 = ri->domain;
125 	ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = ri->src_addr;
126 	ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = ri->dst_addr;
127 	ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].value.u16 = ri->src_port_low;
128 	ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].value.u16 = ri->dst_port_low;
129 
130 	ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].mask_range.u8 = ri->proto_mask;
131 	ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].mask_range.u16 = ri->vlan_mask;
132 	ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].mask_range.u16 =
133 		ri->domain_mask;
134 	ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 =
135 		ri->src_mask_len;
136 	ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = ri->dst_mask_len;
137 	ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].mask_range.u16 =
138 		ri->src_port_high;
139 	ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].mask_range.u16 =
140 		ri->dst_port_high;
141 }
142 
143 /*
144  * Add ipv4vlan rules to an existing ACL context.
145  * This function is not multi-thread safe.
146  *
147  * @param ctx
148  *   ACL context to add patterns to.
149  * @param rules
150  *   Array of rules to add to the ACL context.
151  *   Note that all fields in rte_acl_ipv4vlan_rule structures are expected
152  *   to be in host byte order.
153  * @param num
154  *   Number of elements in the input array of rules.
155  * @return
156  *   - -ENOMEM if there is no space in the ACL context for these rules.
157  *   - -EINVAL if the parameters are invalid.
158  *   - Zero if operation completed successfully.
159  */
160 static int
161 rte_acl_ipv4vlan_add_rules(struct rte_acl_ctx *ctx,
162 	const struct rte_acl_ipv4vlan_rule *rules,
163 	uint32_t num)
164 {
165 	int32_t rc;
166 	uint32_t i;
167 	struct acl_ipv4vlan_rule rv;
168 
169 	if (ctx == NULL || rules == NULL)
170 		return -EINVAL;
171 
172 	/* check input rules. */
173 	for (i = 0; i != num; i++) {
174 		rc = acl_ipv4vlan_check_rule(rules + i);
175 		if (rc != 0) {
176 			RTE_LOG(ERR, ACL, "%s: rule #%u is invalid\n",
177 				__func__, i + 1);
178 			return rc;
179 		}
180 	}
181 
182 	/* perform conversion to the internal format and add to the context. */
183 	for (i = 0, rc = 0; i != num && rc == 0; i++) {
184 		acl_ipv4vlan_convert_rule(rules + i, &rv);
185 		rc = rte_acl_add_rules(ctx, (struct rte_acl_rule *)&rv, 1);
186 	}
187 
188 	return rc;
189 }
190 
191 static void
192 acl_ipv4vlan_config(struct rte_acl_config *cfg,
193 	const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],
194 	uint32_t num_categories)
195 {
196 	static const struct rte_acl_field_def
197 		ipv4_defs[RTE_ACL_IPV4VLAN_NUM_FIELDS] = {
198 		{
199 			.type = RTE_ACL_FIELD_TYPE_BITMASK,
200 			.size = sizeof(uint8_t),
201 			.field_index = RTE_ACL_IPV4VLAN_PROTO_FIELD,
202 			.input_index = RTE_ACL_IPV4VLAN_PROTO,
203 		},
204 		{
205 			.type = RTE_ACL_FIELD_TYPE_BITMASK,
206 			.size = sizeof(uint16_t),
207 			.field_index = RTE_ACL_IPV4VLAN_VLAN1_FIELD,
208 			.input_index = RTE_ACL_IPV4VLAN_VLAN,
209 		},
210 		{
211 			.type = RTE_ACL_FIELD_TYPE_BITMASK,
212 			.size = sizeof(uint16_t),
213 			.field_index = RTE_ACL_IPV4VLAN_VLAN2_FIELD,
214 			.input_index = RTE_ACL_IPV4VLAN_VLAN,
215 		},
216 		{
217 			.type = RTE_ACL_FIELD_TYPE_MASK,
218 			.size = sizeof(uint32_t),
219 			.field_index = RTE_ACL_IPV4VLAN_SRC_FIELD,
220 			.input_index = RTE_ACL_IPV4VLAN_SRC,
221 		},
222 		{
223 			.type = RTE_ACL_FIELD_TYPE_MASK,
224 			.size = sizeof(uint32_t),
225 			.field_index = RTE_ACL_IPV4VLAN_DST_FIELD,
226 			.input_index = RTE_ACL_IPV4VLAN_DST,
227 		},
228 		{
229 			.type = RTE_ACL_FIELD_TYPE_RANGE,
230 			.size = sizeof(uint16_t),
231 			.field_index = RTE_ACL_IPV4VLAN_SRCP_FIELD,
232 			.input_index = RTE_ACL_IPV4VLAN_PORTS,
233 		},
234 		{
235 			.type = RTE_ACL_FIELD_TYPE_RANGE,
236 			.size = sizeof(uint16_t),
237 			.field_index = RTE_ACL_IPV4VLAN_DSTP_FIELD,
238 			.input_index = RTE_ACL_IPV4VLAN_PORTS,
239 		},
240 	};
241 
242 	memcpy(&cfg->defs, ipv4_defs, sizeof(ipv4_defs));
243 	cfg->num_fields = RTE_DIM(ipv4_defs);
244 
245 	cfg->defs[RTE_ACL_IPV4VLAN_PROTO_FIELD].offset =
246 		layout[RTE_ACL_IPV4VLAN_PROTO];
247 	cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].offset =
248 		layout[RTE_ACL_IPV4VLAN_VLAN];
249 	cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].offset =
250 		layout[RTE_ACL_IPV4VLAN_VLAN] +
251 		cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].size;
252 	cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].offset =
253 		layout[RTE_ACL_IPV4VLAN_SRC];
254 	cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset =
255 		layout[RTE_ACL_IPV4VLAN_DST];
256 	cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset =
257 		layout[RTE_ACL_IPV4VLAN_PORTS];
258 	cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset =
259 		layout[RTE_ACL_IPV4VLAN_PORTS] +
260 		cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size;
261 
262 	cfg->num_categories = num_categories;
263 }
264 
265 /*
266  * Analyze set of ipv4vlan rules and build required internal
267  * run-time structures.
268  * This function is not multi-thread safe.
269  *
270  * @param ctx
271  *   ACL context to build.
272  * @param layout
273  *   Layout of input data to search through.
274  * @param num_categories
275  *   Maximum number of categories to use in that build.
276  * @return
277  *   - -ENOMEM if couldn't allocate enough memory.
278  *   - -EINVAL if the parameters are invalid.
279  *   - Negative error code if operation failed.
280  *   - Zero if operation completed successfully.
281  */
282 static int
283 rte_acl_ipv4vlan_build(struct rte_acl_ctx *ctx,
284 	const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],
285 	uint32_t num_categories)
286 {
287 	struct rte_acl_config cfg;
288 
289 	if (ctx == NULL || layout == NULL)
290 		return -EINVAL;
291 
292 	memset(&cfg, 0, sizeof(cfg));
293 	acl_ipv4vlan_config(&cfg, layout, num_categories);
294 	return rte_acl_build(ctx, &cfg);
295 }
296 
297 /*
298  * Test scalar and SSE ACL lookup.
299  */
300 static int
301 test_classify_run(struct rte_acl_ctx *acx)
302 {
303 	int ret, i;
304 	uint32_t result, count;
305 	uint32_t results[RTE_DIM(acl_test_data) * RTE_ACL_MAX_CATEGORIES];
306 	const uint8_t *data[RTE_DIM(acl_test_data)];
307 
308 	/* swap all bytes in the data to network order */
309 	bswap_test_data(acl_test_data, RTE_DIM(acl_test_data), 1);
310 
311 	/* store pointers to test data */
312 	for (i = 0; i < (int) RTE_DIM(acl_test_data); i++)
313 		data[i] = (uint8_t *)&acl_test_data[i];
314 
315 	/**
316 	 * these will run quite a few times, it's necessary to test code paths
317 	 * from num=0 to num>8
318 	 */
319 	for (count = 0; count <= RTE_DIM(acl_test_data); count++) {
320 		ret = rte_acl_classify(acx, data, results,
321 				count, RTE_ACL_MAX_CATEGORIES);
322 		if (ret != 0) {
323 			printf("Line %i: SSE classify failed!\n", __LINE__);
324 			goto err;
325 		}
326 
327 		/* check if we allow everything we should allow */
328 		for (i = 0; i < (int) count; i++) {
329 			result =
330 				results[i * RTE_ACL_MAX_CATEGORIES + ACL_ALLOW];
331 			if (result != acl_test_data[i].allow) {
332 				printf("Line %i: Error in allow results at %i "
333 					"(expected %"PRIu32" got %"PRIu32")!\n",
334 					__LINE__, i, acl_test_data[i].allow,
335 					result);
336 				ret = -EINVAL;
337 				goto err;
338 			}
339 		}
340 
341 		/* check if we deny everything we should deny */
342 		for (i = 0; i < (int) count; i++) {
343 			result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_DENY];
344 			if (result != acl_test_data[i].deny) {
345 				printf("Line %i: Error in deny results at %i "
346 					"(expected %"PRIu32" got %"PRIu32")!\n",
347 					__LINE__, i, acl_test_data[i].deny,
348 					result);
349 				ret = -EINVAL;
350 				goto err;
351 			}
352 		}
353 	}
354 
355 	/* make a quick check for scalar */
356 	ret = rte_acl_classify_alg(acx, data, results,
357 			RTE_DIM(acl_test_data), RTE_ACL_MAX_CATEGORIES,
358 			RTE_ACL_CLASSIFY_SCALAR);
359 	if (ret != 0) {
360 		printf("Line %i: scalar classify failed!\n", __LINE__);
361 		goto err;
362 	}
363 
364 	/* check if we allow everything we should allow */
365 	for (i = 0; i < (int) RTE_DIM(acl_test_data); i++) {
366 		result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_ALLOW];
367 		if (result != acl_test_data[i].allow) {
368 			printf("Line %i: Error in allow results at %i "
369 					"(expected %"PRIu32" got %"PRIu32")!\n",
370 					__LINE__, i, acl_test_data[i].allow,
371 					result);
372 			ret = -EINVAL;
373 			goto err;
374 		}
375 	}
376 
377 	/* check if we deny everything we should deny */
378 	for (i = 0; i < (int) RTE_DIM(acl_test_data); i++) {
379 		result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_DENY];
380 		if (result != acl_test_data[i].deny) {
381 			printf("Line %i: Error in deny results at %i "
382 					"(expected %"PRIu32" got %"PRIu32")!\n",
383 					__LINE__, i, acl_test_data[i].deny,
384 					result);
385 			ret = -EINVAL;
386 			goto err;
387 		}
388 	}
389 
390 	ret = 0;
391 
392 err:
393 	/* swap data back to cpu order so that next time tests don't fail */
394 	bswap_test_data(acl_test_data, RTE_DIM(acl_test_data), 0);
395 	return ret;
396 }
397 
398 static int
399 test_classify_buid(struct rte_acl_ctx *acx,
400 	const struct rte_acl_ipv4vlan_rule *rules, uint32_t num)
401 {
402 	int ret;
403 
404 	/* add rules to the context */
405 	ret = rte_acl_ipv4vlan_add_rules(acx, rules, num);
406 	if (ret != 0) {
407 		printf("Line %i: Adding rules to ACL context failed!\n",
408 			__LINE__);
409 		return ret;
410 	}
411 
412 	/* try building the context */
413 	ret = rte_acl_ipv4vlan_build(acx, ipv4_7tuple_layout,
414 		RTE_ACL_MAX_CATEGORIES);
415 	if (ret != 0) {
416 		printf("Line %i: Building ACL context failed!\n", __LINE__);
417 		return ret;
418 	}
419 
420 	return 0;
421 }
422 
423 #define	TEST_CLASSIFY_ITER	4
424 
425 /*
426  * Test scalar and SSE ACL lookup.
427  */
428 static int
429 test_classify(void)
430 {
431 	struct rte_acl_ctx *acx;
432 	int i, ret;
433 
434 	acx = rte_acl_create(&acl_param);
435 	if (acx == NULL) {
436 		printf("Line %i: Error creating ACL context!\n", __LINE__);
437 		return -1;
438 	}
439 
440 	ret = 0;
441 	for (i = 0; i != TEST_CLASSIFY_ITER; i++) {
442 
443 		if ((i & 1) == 0)
444 			rte_acl_reset(acx);
445 		else
446 			rte_acl_reset_rules(acx);
447 
448 		ret = test_classify_buid(acx, acl_test_rules,
449 			RTE_DIM(acl_test_rules));
450 		if (ret != 0) {
451 			printf("Line %i, iter: %d: "
452 				"Adding rules to ACL context failed!\n",
453 				__LINE__, i);
454 			break;
455 		}
456 
457 		ret = test_classify_run(acx);
458 		if (ret != 0) {
459 			printf("Line %i, iter: %d: %s failed!\n",
460 				__LINE__, i, __func__);
461 			break;
462 		}
463 
464 		/* reset rules and make sure that classify still works ok. */
465 		rte_acl_reset_rules(acx);
466 		ret = test_classify_run(acx);
467 		if (ret != 0) {
468 			printf("Line %i, iter: %d: %s failed!\n",
469 				__LINE__, i, __func__);
470 			break;
471 		}
472 	}
473 
474 	rte_acl_free(acx);
475 	return ret;
476 }
477 
478 static int
479 test_build_ports_range(void)
480 {
481 	static const struct rte_acl_ipv4vlan_rule test_rules[] = {
482 		{
483 			/* match all packets. */
484 			.data = {
485 				.userdata = 1,
486 				.category_mask = ACL_ALLOW_MASK,
487 				.priority = 101,
488 			},
489 			.src_port_low = 0,
490 			.src_port_high = UINT16_MAX,
491 			.dst_port_low = 0,
492 			.dst_port_high = UINT16_MAX,
493 		},
494 		{
495 			/* match all packets with dst ports [54-65280]. */
496 			.data = {
497 				.userdata = 2,
498 				.category_mask = ACL_ALLOW_MASK,
499 				.priority = 102,
500 			},
501 			.src_port_low = 0,
502 			.src_port_high = UINT16_MAX,
503 			.dst_port_low = 54,
504 			.dst_port_high = 65280,
505 		},
506 		{
507 			/* match all packets with dst ports [0-52]. */
508 			.data = {
509 				.userdata = 3,
510 				.category_mask = ACL_ALLOW_MASK,
511 				.priority = 103,
512 			},
513 			.src_port_low = 0,
514 			.src_port_high = UINT16_MAX,
515 			.dst_port_low = 0,
516 			.dst_port_high = 52,
517 		},
518 		{
519 			/* match all packets with dst ports [53]. */
520 			.data = {
521 				.userdata = 4,
522 				.category_mask = ACL_ALLOW_MASK,
523 				.priority = 99,
524 			},
525 			.src_port_low = 0,
526 			.src_port_high = UINT16_MAX,
527 			.dst_port_low = 53,
528 			.dst_port_high = 53,
529 		},
530 		{
531 			/* match all packets with dst ports [65279-65535]. */
532 			.data = {
533 				.userdata = 5,
534 				.category_mask = ACL_ALLOW_MASK,
535 				.priority = 98,
536 			},
537 			.src_port_low = 0,
538 			.src_port_high = UINT16_MAX,
539 			.dst_port_low = 65279,
540 			.dst_port_high = UINT16_MAX,
541 		},
542 	};
543 
544 	static struct ipv4_7tuple test_data[] = {
545 		{
546 			.proto = 6,
547 			.ip_src = IPv4(10, 1, 1, 1),
548 			.ip_dst = IPv4(192, 168, 0, 33),
549 			.port_dst = 53,
550 			.allow = 1,
551 		},
552 		{
553 			.proto = 6,
554 			.ip_src = IPv4(127, 84, 33, 1),
555 			.ip_dst = IPv4(1, 2, 3, 4),
556 			.port_dst = 65281,
557 			.allow = 1,
558 		},
559 	};
560 
561 	struct rte_acl_ctx *acx;
562 	int32_t ret, i, j;
563 	uint32_t results[RTE_DIM(test_data)];
564 	const uint8_t *data[RTE_DIM(test_data)];
565 
566 	acx = rte_acl_create(&acl_param);
567 	if (acx == NULL) {
568 		printf("Line %i: Error creating ACL context!\n", __LINE__);
569 		return -1;
570 	}
571 
572 	/* swap all bytes in the data to network order */
573 	bswap_test_data(test_data, RTE_DIM(test_data), 1);
574 
575 	/* store pointers to test data */
576 	for (i = 0; i != RTE_DIM(test_data); i++)
577 		data[i] = (uint8_t *)&test_data[i];
578 
579 	for (i = 0; i != RTE_DIM(test_rules); i++) {
580 		rte_acl_reset(acx);
581 		ret = test_classify_buid(acx, test_rules, i + 1);
582 		if (ret != 0) {
583 			printf("Line %i, iter: %d: "
584 				"Adding rules to ACL context failed!\n",
585 				__LINE__, i);
586 			break;
587 		}
588 		ret = rte_acl_classify(acx, data, results,
589 			RTE_DIM(data), 1);
590 		if (ret != 0) {
591 			printf("Line %i, iter: %d: classify failed!\n",
592 				__LINE__, i);
593 			break;
594 		}
595 
596 		/* check results */
597 		for (j = 0; j != RTE_DIM(results); j++) {
598 			if (results[j] != test_data[j].allow) {
599 				printf("Line %i: Error in allow results at %i "
600 					"(expected %"PRIu32" got %"PRIu32")!\n",
601 					__LINE__, j, test_data[j].allow,
602 					results[j]);
603 				ret = -EINVAL;
604 			}
605 		}
606 	}
607 
608 	bswap_test_data(test_data, RTE_DIM(test_data), 0);
609 
610 	rte_acl_free(acx);
611 	return ret;
612 }
613 
614 static void
615 convert_rule(const struct rte_acl_ipv4vlan_rule *ri,
616 	struct acl_ipv4vlan_rule *ro)
617 {
618 	ro->data = ri->data;
619 
620 	ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].value.u8 = ri->proto;
621 	ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].value.u16 = ri->vlan;
622 	ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].value.u16 = ri->domain;
623 	ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = ri->src_addr;
624 	ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = ri->dst_addr;
625 	ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].value.u16 = ri->src_port_low;
626 	ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].value.u16 = ri->dst_port_low;
627 
628 	ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].mask_range.u8 = ri->proto_mask;
629 	ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].mask_range.u16 = ri->vlan_mask;
630 	ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].mask_range.u16 =
631 		ri->domain_mask;
632 	ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 =
633 		ri->src_mask_len;
634 	ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = ri->dst_mask_len;
635 	ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].mask_range.u16 =
636 		ri->src_port_high;
637 	ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].mask_range.u16 =
638 		ri->dst_port_high;
639 }
640 
641 /*
642  * Convert IPV4 source and destination from RTE_ACL_FIELD_TYPE_MASK to
643  * RTE_ACL_FIELD_TYPE_BITMASK.
644  */
645 static void
646 convert_rule_1(const struct rte_acl_ipv4vlan_rule *ri,
647 	struct acl_ipv4vlan_rule *ro)
648 {
649 	uint32_t v;
650 
651 	convert_rule(ri, ro);
652 	v = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32;
653 	ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 =
654 		RTE_ACL_MASKLEN_TO_BITMASK(v, sizeof(v));
655 	v = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32;
656 	ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 =
657 		RTE_ACL_MASKLEN_TO_BITMASK(v, sizeof(v));
658 }
659 
660 /*
661  * Convert IPV4 source and destination from RTE_ACL_FIELD_TYPE_MASK to
662  * RTE_ACL_FIELD_TYPE_RANGE.
663  */
664 static void
665 convert_rule_2(const struct rte_acl_ipv4vlan_rule *ri,
666 	struct acl_ipv4vlan_rule *ro)
667 {
668 	uint32_t hi, lo, mask;
669 
670 	convert_rule(ri, ro);
671 
672 	mask = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32;
673 	mask = RTE_ACL_MASKLEN_TO_BITMASK(mask, sizeof(mask));
674 	lo = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 & mask;
675 	hi = lo + ~mask;
676 	ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = lo;
677 	ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 = hi;
678 
679 	mask = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32;
680 	mask = RTE_ACL_MASKLEN_TO_BITMASK(mask, sizeof(mask));
681 	lo = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 & mask;
682 	hi = lo + ~mask;
683 	ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = lo;
684 	ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = hi;
685 }
686 
687 /*
688  * Convert rte_acl_ipv4vlan_rule: swap VLAN and PORTS rule fields.
689  */
690 static void
691 convert_rule_3(const struct rte_acl_ipv4vlan_rule *ri,
692 	struct acl_ipv4vlan_rule *ro)
693 {
694 	struct rte_acl_field t1, t2;
695 
696 	convert_rule(ri, ro);
697 
698 	t1 = ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD];
699 	t2 = ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD];
700 
701 	ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD] =
702 		ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD];
703 	ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD] =
704 		ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD];
705 
706 	ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD] = t1;
707 	ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD] = t2;
708 }
709 
710 /*
711  * Convert rte_acl_ipv4vlan_rule: swap SRC and DST IPv4 address rules.
712  */
713 static void
714 convert_rule_4(const struct rte_acl_ipv4vlan_rule *ri,
715 	struct acl_ipv4vlan_rule *ro)
716 {
717 	struct rte_acl_field t;
718 
719 	convert_rule(ri, ro);
720 
721 	t = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD];
722 	ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD] =
723 		ro->field[RTE_ACL_IPV4VLAN_DST_FIELD];
724 
725 	ro->field[RTE_ACL_IPV4VLAN_DST_FIELD] = t;
726 }
727 
728 static void
729 ipv4vlan_config(struct rte_acl_config *cfg,
730 	const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],
731 	uint32_t num_categories)
732 {
733 	static const struct rte_acl_field_def
734 		ipv4_defs[RTE_ACL_IPV4VLAN_NUM_FIELDS] = {
735 		{
736 			.type = RTE_ACL_FIELD_TYPE_BITMASK,
737 			.size = sizeof(uint8_t),
738 			.field_index = RTE_ACL_IPV4VLAN_PROTO_FIELD,
739 			.input_index = RTE_ACL_IPV4VLAN_PROTO,
740 		},
741 		{
742 			.type = RTE_ACL_FIELD_TYPE_BITMASK,
743 			.size = sizeof(uint16_t),
744 			.field_index = RTE_ACL_IPV4VLAN_VLAN1_FIELD,
745 			.input_index = RTE_ACL_IPV4VLAN_VLAN,
746 		},
747 		{
748 			.type = RTE_ACL_FIELD_TYPE_BITMASK,
749 			.size = sizeof(uint16_t),
750 			.field_index = RTE_ACL_IPV4VLAN_VLAN2_FIELD,
751 			.input_index = RTE_ACL_IPV4VLAN_VLAN,
752 		},
753 		{
754 			.type = RTE_ACL_FIELD_TYPE_MASK,
755 			.size = sizeof(uint32_t),
756 			.field_index = RTE_ACL_IPV4VLAN_SRC_FIELD,
757 			.input_index = RTE_ACL_IPV4VLAN_SRC,
758 		},
759 		{
760 			.type = RTE_ACL_FIELD_TYPE_MASK,
761 			.size = sizeof(uint32_t),
762 			.field_index = RTE_ACL_IPV4VLAN_DST_FIELD,
763 			.input_index = RTE_ACL_IPV4VLAN_DST,
764 		},
765 		{
766 			.type = RTE_ACL_FIELD_TYPE_RANGE,
767 			.size = sizeof(uint16_t),
768 			.field_index = RTE_ACL_IPV4VLAN_SRCP_FIELD,
769 			.input_index = RTE_ACL_IPV4VLAN_PORTS,
770 		},
771 		{
772 			.type = RTE_ACL_FIELD_TYPE_RANGE,
773 			.size = sizeof(uint16_t),
774 			.field_index = RTE_ACL_IPV4VLAN_DSTP_FIELD,
775 			.input_index = RTE_ACL_IPV4VLAN_PORTS,
776 		},
777 	};
778 
779 	memcpy(&cfg->defs, ipv4_defs, sizeof(ipv4_defs));
780 	cfg->num_fields = RTE_DIM(ipv4_defs);
781 
782 	cfg->defs[RTE_ACL_IPV4VLAN_PROTO_FIELD].offset =
783 		layout[RTE_ACL_IPV4VLAN_PROTO];
784 	cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].offset =
785 		layout[RTE_ACL_IPV4VLAN_VLAN];
786 	cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].offset =
787 		layout[RTE_ACL_IPV4VLAN_VLAN] +
788 		cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].size;
789 	cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].offset =
790 		layout[RTE_ACL_IPV4VLAN_SRC];
791 	cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset =
792 		layout[RTE_ACL_IPV4VLAN_DST];
793 	cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset =
794 		layout[RTE_ACL_IPV4VLAN_PORTS];
795 	cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset =
796 		layout[RTE_ACL_IPV4VLAN_PORTS] +
797 		cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size;
798 
799 	cfg->num_categories = num_categories;
800 }
801 
802 static int
803 convert_rules(struct rte_acl_ctx *acx,
804 	void (*convert)(const struct rte_acl_ipv4vlan_rule *,
805 	struct acl_ipv4vlan_rule *),
806 	const struct rte_acl_ipv4vlan_rule *rules, uint32_t num)
807 {
808 	int32_t rc;
809 	uint32_t i;
810 	struct acl_ipv4vlan_rule r;
811 
812 	for (i = 0; i != num; i++) {
813 		convert(rules + i, &r);
814 		rc = rte_acl_add_rules(acx, (struct rte_acl_rule *)&r, 1);
815 		if (rc != 0) {
816 			printf("Line %i: Adding rule %u to ACL context "
817 				"failed with error code: %d\n",
818 			__LINE__, i, rc);
819 			return rc;
820 		}
821 	}
822 
823 	return 0;
824 }
825 
826 static void
827 convert_config(struct rte_acl_config *cfg)
828 {
829 	ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
830 }
831 
832 /*
833  * Convert rte_acl_ipv4vlan_rule to use RTE_ACL_FIELD_TYPE_BITMASK.
834  */
835 static void
836 convert_config_1(struct rte_acl_config *cfg)
837 {
838 	ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
839 	cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].type = RTE_ACL_FIELD_TYPE_BITMASK;
840 	cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = RTE_ACL_FIELD_TYPE_BITMASK;
841 }
842 
843 /*
844  * Convert rte_acl_ipv4vlan_rule to use RTE_ACL_FIELD_TYPE_RANGE.
845  */
846 static void
847 convert_config_2(struct rte_acl_config *cfg)
848 {
849 	ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
850 	cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].type = RTE_ACL_FIELD_TYPE_RANGE;
851 	cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = RTE_ACL_FIELD_TYPE_RANGE;
852 }
853 
854 /*
855  * Convert rte_acl_ipv4vlan_rule: swap VLAN and PORTS rule definitions.
856  */
857 static void
858 convert_config_3(struct rte_acl_config *cfg)
859 {
860 	struct rte_acl_field_def t1, t2;
861 
862 	ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
863 
864 	t1 = cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD];
865 	t2 = cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD];
866 
867 	/* swap VLAN1 and SRCP rule definition. */
868 	cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD] =
869 		cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD];
870 	cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].field_index = t1.field_index;
871 	cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].input_index = t1.input_index;
872 
873 	/* swap VLAN2 and DSTP rule definition. */
874 	cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD] =
875 		cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD];
876 	cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].field_index = t2.field_index;
877 	cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].input_index = t2.input_index;
878 
879 	cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].type = t1.type;
880 	cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size = t1.size;
881 	cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset = t1.offset;
882 
883 	cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].type = t2.type;
884 	cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].size = t2.size;
885 	cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset = t2.offset;
886 }
887 
888 /*
889  * Convert rte_acl_ipv4vlan_rule: swap SRC and DST ip address rule definitions.
890  */
891 static void
892 convert_config_4(struct rte_acl_config *cfg)
893 {
894 	struct rte_acl_field_def t;
895 
896 	ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
897 
898 	t = cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD];
899 
900 	cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD] =
901 		cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD];
902 	cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].field_index = t.field_index;
903 	cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].input_index = t.input_index;
904 
905 	cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = t.type;
906 	cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].size = t.size;
907 	cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset = t.offset;
908 }
909 
910 
911 static int
912 build_convert_rules(struct rte_acl_ctx *acx,
913 	void (*config)(struct rte_acl_config *),
914 	size_t max_size)
915 {
916 	struct rte_acl_config cfg;
917 
918 	memset(&cfg, 0, sizeof(cfg));
919 	config(&cfg);
920 	cfg.max_size = max_size;
921 	return rte_acl_build(acx, &cfg);
922 }
923 
924 static int
925 test_convert_rules(const char *desc,
926 	void (*config)(struct rte_acl_config *),
927 	void (*convert)(const struct rte_acl_ipv4vlan_rule *,
928 	struct acl_ipv4vlan_rule *))
929 {
930 	struct rte_acl_ctx *acx;
931 	int32_t rc;
932 	uint32_t i;
933 	static const size_t mem_sizes[] = {0, -1};
934 
935 	printf("running %s(%s)\n", __func__, desc);
936 
937 	acx = rte_acl_create(&acl_param);
938 	if (acx == NULL) {
939 		printf("Line %i: Error creating ACL context!\n", __LINE__);
940 		return -1;
941 	}
942 
943 	rc = convert_rules(acx, convert, acl_test_rules,
944 		RTE_DIM(acl_test_rules));
945 	if (rc != 0)
946 		printf("Line %i: Error converting ACL rules!\n", __LINE__);
947 
948 	for (i = 0; rc == 0 && i != RTE_DIM(mem_sizes); i++) {
949 
950 		rc = build_convert_rules(acx, config, mem_sizes[i]);
951 		if (rc != 0) {
952 			printf("Line %i: Error @ build_convert_rules(%zu)!\n",
953 				__LINE__, mem_sizes[i]);
954 			break;
955 		}
956 
957 		rc = test_classify_run(acx);
958 		if (rc != 0)
959 			printf("%s failed at line %i, max_size=%zu\n",
960 				__func__, __LINE__, mem_sizes[i]);
961 	}
962 
963 	rte_acl_free(acx);
964 	return rc;
965 }
966 
967 static int
968 test_convert(void)
969 {
970 	static const struct {
971 		const char *desc;
972 		void (*config)(struct rte_acl_config *);
973 		void (*convert)(const struct rte_acl_ipv4vlan_rule *,
974 			struct acl_ipv4vlan_rule *);
975 	} convert_param[] = {
976 		{
977 			"acl_ipv4vlan_tuple",
978 			convert_config,
979 			convert_rule,
980 		},
981 		{
982 			"acl_ipv4vlan_tuple, RTE_ACL_FIELD_TYPE_BITMASK type "
983 			"for IPv4",
984 			convert_config_1,
985 			convert_rule_1,
986 		},
987 		{
988 			"acl_ipv4vlan_tuple, RTE_ACL_FIELD_TYPE_RANGE type "
989 			"for IPv4",
990 			convert_config_2,
991 			convert_rule_2,
992 		},
993 		{
994 			"acl_ipv4vlan_tuple: swap VLAN and PORTs order",
995 			convert_config_3,
996 			convert_rule_3,
997 		},
998 		{
999 			"acl_ipv4vlan_tuple: swap SRC and DST IPv4 order",
1000 			convert_config_4,
1001 			convert_rule_4,
1002 		},
1003 	};
1004 
1005 	uint32_t i;
1006 	int32_t rc;
1007 
1008 	for (i = 0; i != RTE_DIM(convert_param); i++) {
1009 		rc = test_convert_rules(convert_param[i].desc,
1010 			convert_param[i].config,
1011 			convert_param[i].convert);
1012 		if (rc != 0) {
1013 			printf("%s for test-case: %s failed, error code: %d;\n",
1014 				__func__, convert_param[i].desc, rc);
1015 			return rc;
1016 		}
1017 	}
1018 
1019 	return 0;
1020 }
1021 
1022 /*
1023  * Test wrong layout behavior
1024  * This test supplies the ACL context with invalid layout, which results in
1025  * ACL matching the wrong stuff. However, it should match the wrong stuff
1026  * the right way. We switch around source and destination addresses,
1027  * source and destination ports, and protocol will point to first byte of
1028  * destination port.
1029  */
1030 static int
1031 test_invalid_layout(void)
1032 {
1033 	struct rte_acl_ctx *acx;
1034 	int ret, i;
1035 
1036 	uint32_t results[RTE_DIM(invalid_layout_data)];
1037 	const uint8_t *data[RTE_DIM(invalid_layout_data)];
1038 
1039 	const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {
1040 			/* proto points to destination port's first byte */
1041 			offsetof(struct ipv4_7tuple, port_dst),
1042 
1043 			0, /* VLAN not used */
1044 
1045 			/* src and dst addresses are swapped */
1046 			offsetof(struct ipv4_7tuple, ip_dst),
1047 			offsetof(struct ipv4_7tuple, ip_src),
1048 
1049 			/*
1050 			 * we can't swap ports here, so we will swap
1051 			 * them in the data
1052 			 */
1053 			offsetof(struct ipv4_7tuple, port_src),
1054 	};
1055 
1056 	acx = rte_acl_create(&acl_param);
1057 	if (acx == NULL) {
1058 		printf("Line %i: Error creating ACL context!\n", __LINE__);
1059 		return -1;
1060 	}
1061 
1062 	/* putting a lot of rules into the context results in greater
1063 	 * coverage numbers. it doesn't matter if they are identical */
1064 	for (i = 0; i < 1000; i++) {
1065 		/* add rules to the context */
1066 		ret = rte_acl_ipv4vlan_add_rules(acx, invalid_layout_rules,
1067 				RTE_DIM(invalid_layout_rules));
1068 		if (ret != 0) {
1069 			printf("Line %i: Adding rules to ACL context failed!\n",
1070 				__LINE__);
1071 			rte_acl_free(acx);
1072 			return -1;
1073 		}
1074 	}
1075 
1076 	/* try building the context */
1077 	ret = rte_acl_ipv4vlan_build(acx, layout, 1);
1078 	if (ret != 0) {
1079 		printf("Line %i: Building ACL context failed!\n", __LINE__);
1080 		rte_acl_free(acx);
1081 		return -1;
1082 	}
1083 
1084 	/* swap all bytes in the data to network order */
1085 	bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 1);
1086 
1087 	/* prepare data */
1088 	for (i = 0; i < (int) RTE_DIM(invalid_layout_data); i++) {
1089 		data[i] = (uint8_t *)&invalid_layout_data[i];
1090 	}
1091 
1092 	/* classify tuples */
1093 	ret = rte_acl_classify_alg(acx, data, results,
1094 			RTE_DIM(results), 1, RTE_ACL_CLASSIFY_SCALAR);
1095 	if (ret != 0) {
1096 		printf("Line %i: SSE classify failed!\n", __LINE__);
1097 		rte_acl_free(acx);
1098 		return -1;
1099 	}
1100 
1101 	for (i = 0; i < (int) RTE_DIM(results); i++) {
1102 		if (results[i] != invalid_layout_data[i].allow) {
1103 			printf("Line %i: Wrong results at %i "
1104 				"(result=%u, should be %u)!\n",
1105 				__LINE__, i, results[i],
1106 				invalid_layout_data[i].allow);
1107 			goto err;
1108 		}
1109 	}
1110 
1111 	/* classify tuples (scalar) */
1112 	ret = rte_acl_classify_alg(acx, data, results, RTE_DIM(results), 1,
1113 		RTE_ACL_CLASSIFY_SCALAR);
1114 
1115 	if (ret != 0) {
1116 		printf("Line %i: Scalar classify failed!\n", __LINE__);
1117 		rte_acl_free(acx);
1118 		return -1;
1119 	}
1120 
1121 	for (i = 0; i < (int) RTE_DIM(results); i++) {
1122 		if (results[i] != invalid_layout_data[i].allow) {
1123 			printf("Line %i: Wrong results at %i "
1124 				"(result=%u, should be %u)!\n",
1125 				__LINE__, i, results[i],
1126 				invalid_layout_data[i].allow);
1127 			goto err;
1128 		}
1129 	}
1130 
1131 	rte_acl_free(acx);
1132 
1133 	/* swap data back to cpu order so that next time tests don't fail */
1134 	bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 0);
1135 
1136 	return 0;
1137 err:
1138 
1139 	/* swap data back to cpu order so that next time tests don't fail */
1140 	bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 0);
1141 
1142 	rte_acl_free(acx);
1143 
1144 	return -1;
1145 }
1146 
1147 /*
1148  * Test creating and finding ACL contexts, and adding rules
1149  */
1150 static int
1151 test_create_find_add(void)
1152 {
1153 	struct rte_acl_param param;
1154 	struct rte_acl_ctx *acx, *acx2, *tmp;
1155 	struct rte_acl_ipv4vlan_rule rules[LEN];
1156 
1157 	const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0};
1158 
1159 	const char *acx_name = "acx";
1160 	const char *acx2_name = "acx2";
1161 	int i, ret;
1162 
1163 	/* create two contexts */
1164 	memcpy(&param, &acl_param, sizeof(param));
1165 	param.max_rule_num = 2;
1166 
1167 	param.name = acx_name;
1168 	acx = rte_acl_create(&param);
1169 	if (acx == NULL) {
1170 		printf("Line %i: Error creating %s!\n", __LINE__, acx_name);
1171 		return -1;
1172 	}
1173 
1174 	param.name = acx2_name;
1175 	acx2 = rte_acl_create(&param);
1176 	if (acx2 == NULL || acx2 == acx) {
1177 		printf("Line %i: Error creating %s!\n", __LINE__, acx2_name);
1178 		rte_acl_free(acx);
1179 		return -1;
1180 	}
1181 
1182 	/* try to create third one, with an existing name */
1183 	param.name = acx_name;
1184 	tmp = rte_acl_create(&param);
1185 	if (tmp != acx) {
1186 		printf("Line %i: Creating context with existing name "
1187 			"test failed!\n",
1188 			__LINE__);
1189 		if (tmp)
1190 			rte_acl_free(tmp);
1191 		goto err;
1192 	}
1193 
1194 	param.name = acx2_name;
1195 	tmp = rte_acl_create(&param);
1196 	if (tmp != acx2) {
1197 		printf("Line %i: Creating context with existing "
1198 			"name test 2 failed!\n",
1199 			__LINE__);
1200 		if (tmp)
1201 			rte_acl_free(tmp);
1202 		goto err;
1203 	}
1204 
1205 	/* try to find existing ACL contexts */
1206 	tmp = rte_acl_find_existing(acx_name);
1207 	if (tmp != acx) {
1208 		printf("Line %i: Finding %s failed!\n", __LINE__, acx_name);
1209 		if (tmp)
1210 			rte_acl_free(tmp);
1211 		goto err;
1212 	}
1213 
1214 	tmp = rte_acl_find_existing(acx2_name);
1215 	if (tmp != acx2) {
1216 		printf("Line %i: Finding %s failed!\n", __LINE__, acx2_name);
1217 		if (tmp)
1218 			rte_acl_free(tmp);
1219 		goto err;
1220 	}
1221 
1222 	/* try to find non-existing context */
1223 	tmp = rte_acl_find_existing("invalid");
1224 	if (tmp != NULL) {
1225 		printf("Line %i: Non-existent ACL context found!\n", __LINE__);
1226 		goto err;
1227 	}
1228 
1229 	/* free context */
1230 	rte_acl_free(acx);
1231 
1232 
1233 	/* create valid (but severely limited) acx */
1234 	memcpy(&param, &acl_param, sizeof(param));
1235 	param.max_rule_num = LEN;
1236 
1237 	acx = rte_acl_create(&param);
1238 	if (acx == NULL) {
1239 		printf("Line %i: Error creating %s!\n", __LINE__, param.name);
1240 		goto err;
1241 	}
1242 
1243 	/* create dummy acl */
1244 	for (i = 0; i < LEN; i++) {
1245 		memcpy(&rules[i], &acl_rule,
1246 			sizeof(struct rte_acl_ipv4vlan_rule));
1247 		/* skip zero */
1248 		rules[i].data.userdata = i + 1;
1249 		/* one rule per category */
1250 		rules[i].data.category_mask = 1 << i;
1251 	}
1252 
1253 	/* try filling up the context */
1254 	ret = rte_acl_ipv4vlan_add_rules(acx, rules, LEN);
1255 	if (ret != 0) {
1256 		printf("Line %i: Adding %i rules to ACL context failed!\n",
1257 				__LINE__, LEN);
1258 		goto err;
1259 	}
1260 
1261 	/* try adding to a (supposedly) full context */
1262 	ret = rte_acl_ipv4vlan_add_rules(acx, rules, 1);
1263 	if (ret == 0) {
1264 		printf("Line %i: Adding rules to full ACL context should"
1265 				"have failed!\n", __LINE__);
1266 		goto err;
1267 	}
1268 
1269 	/* try building the context */
1270 	ret = rte_acl_ipv4vlan_build(acx, layout, RTE_ACL_MAX_CATEGORIES);
1271 	if (ret != 0) {
1272 		printf("Line %i: Building ACL context failed!\n", __LINE__);
1273 		goto err;
1274 	}
1275 
1276 	rte_acl_free(acx);
1277 	rte_acl_free(acx2);
1278 
1279 	return 0;
1280 err:
1281 	rte_acl_free(acx);
1282 	rte_acl_free(acx2);
1283 	return -1;
1284 }
1285 
1286 /*
1287  * test various invalid rules
1288  */
1289 static int
1290 test_invalid_rules(void)
1291 {
1292 	struct rte_acl_ctx *acx;
1293 	int ret;
1294 
1295 	struct rte_acl_ipv4vlan_rule rule;
1296 
1297 	acx = rte_acl_create(&acl_param);
1298 	if (acx == NULL) {
1299 		printf("Line %i: Error creating ACL context!\n", __LINE__);
1300 		return -1;
1301 	}
1302 
1303 	/* test inverted high/low source and destination ports.
1304 	 * originally, there was a problem with memory consumption when using
1305 	 * such rules.
1306 	 */
1307 	/* create dummy acl */
1308 	memcpy(&rule, &acl_rule, sizeof(struct rte_acl_ipv4vlan_rule));
1309 	rule.data.userdata = 1;
1310 	rule.dst_port_low = 0xfff0;
1311 	rule.dst_port_high = 0x0010;
1312 
1313 	/* add rules to context and try to build it */
1314 	ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1315 	if (ret == 0) {
1316 		printf("Line %i: Adding rules to ACL context "
1317 				"should have failed!\n", __LINE__);
1318 		goto err;
1319 	}
1320 
1321 	rule.dst_port_low = 0x0;
1322 	rule.dst_port_high = 0xffff;
1323 	rule.src_port_low = 0xfff0;
1324 	rule.src_port_high = 0x0010;
1325 
1326 	/* add rules to context and try to build it */
1327 	ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1328 	if (ret == 0) {
1329 		printf("Line %i: Adding rules to ACL context "
1330 				"should have failed!\n", __LINE__);
1331 		goto err;
1332 	}
1333 
1334 	rule.dst_port_low = 0x0;
1335 	rule.dst_port_high = 0xffff;
1336 	rule.src_port_low = 0x0;
1337 	rule.src_port_high = 0xffff;
1338 
1339 	rule.dst_mask_len = 33;
1340 
1341 	/* add rules to context and try to build it */
1342 	ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1343 	if (ret == 0) {
1344 		printf("Line %i: Adding rules to ACL context "
1345 				"should have failed!\n", __LINE__);
1346 		goto err;
1347 	}
1348 
1349 	rule.dst_mask_len = 0;
1350 	rule.src_mask_len = 33;
1351 
1352 	/* add rules to context and try to build it */
1353 	ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1354 	if (ret == 0) {
1355 		printf("Line %i: Adding rules to ACL context "
1356 				"should have failed!\n", __LINE__);
1357 		goto err;
1358 	}
1359 
1360 	rule.dst_mask_len = 0;
1361 	rule.src_mask_len = 0;
1362 	rule.data.userdata = 0;
1363 
1364 	/* try adding this rule (it should fail because userdata is invalid) */
1365 	ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1366 	if (ret == 0) {
1367 		printf("Line %i: Adding a rule with invalid user data "
1368 				"should have failed!\n", __LINE__);
1369 		rte_acl_free(acx);
1370 		return -1;
1371 	}
1372 
1373 	rte_acl_free(acx);
1374 
1375 	return 0;
1376 
1377 err:
1378 	rte_acl_free(acx);
1379 
1380 	return -1;
1381 }
1382 
1383 /*
1384  * test functions by passing invalid or
1385  * non-workable parameters.
1386  *
1387  * we do very limited testing of classify functions here
1388  * because those are performance-critical and
1389  * thus don't do much parameter checking.
1390  */
1391 static int
1392 test_invalid_parameters(void)
1393 {
1394 	struct rte_acl_param param;
1395 	struct rte_acl_ctx *acx;
1396 	struct rte_acl_ipv4vlan_rule rule;
1397 	int result;
1398 
1399 	uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0};
1400 
1401 
1402 	/**
1403 	 * rte_ac_create()
1404 	 */
1405 
1406 	/* NULL param */
1407 	acx = rte_acl_create(NULL);
1408 	if (acx != NULL) {
1409 		printf("Line %i: ACL context creation with NULL param "
1410 				"should have failed!\n", __LINE__);
1411 		rte_acl_free(acx);
1412 		return -1;
1413 	}
1414 
1415 	/* zero rule size */
1416 	memcpy(&param, &acl_param, sizeof(param));
1417 	param.rule_size = 0;
1418 
1419 	acx = rte_acl_create(&param);
1420 	if (acx == NULL) {
1421 		printf("Line %i: ACL context creation with zero rule len "
1422 				"failed!\n", __LINE__);
1423 		return -1;
1424 	} else
1425 		rte_acl_free(acx);
1426 
1427 	/* zero max rule num */
1428 	memcpy(&param, &acl_param, sizeof(param));
1429 	param.max_rule_num = 0;
1430 
1431 	acx = rte_acl_create(&param);
1432 	if (acx == NULL) {
1433 		printf("Line %i: ACL context creation with zero rule num "
1434 				"failed!\n", __LINE__);
1435 		return -1;
1436 	} else
1437 		rte_acl_free(acx);
1438 
1439 	/* invalid NUMA node */
1440 	memcpy(&param, &acl_param, sizeof(param));
1441 	param.socket_id = RTE_MAX_NUMA_NODES + 1;
1442 
1443 	acx = rte_acl_create(&param);
1444 	if (acx != NULL) {
1445 		printf("Line %i: ACL context creation with invalid NUMA "
1446 				"should have failed!\n", __LINE__);
1447 		rte_acl_free(acx);
1448 		return -1;
1449 	}
1450 
1451 	/* NULL name */
1452 	memcpy(&param, &acl_param, sizeof(param));
1453 	param.name = NULL;
1454 
1455 	acx = rte_acl_create(&param);
1456 	if (acx != NULL) {
1457 		printf("Line %i: ACL context creation with NULL name "
1458 				"should have failed!\n", __LINE__);
1459 		rte_acl_free(acx);
1460 		return -1;
1461 	}
1462 
1463 	/**
1464 	 * rte_acl_find_existing
1465 	 */
1466 
1467 	acx = rte_acl_find_existing(NULL);
1468 	if (acx != NULL) {
1469 		printf("Line %i: NULL ACL context found!\n", __LINE__);
1470 		rte_acl_free(acx);
1471 		return -1;
1472 	}
1473 
1474 	/**
1475 	 * rte_acl_ipv4vlan_add_rules
1476 	 */
1477 
1478 	/* initialize everything */
1479 	memcpy(&param, &acl_param, sizeof(param));
1480 	acx = rte_acl_create(&param);
1481 	if (acx == NULL) {
1482 		printf("Line %i: ACL context creation failed!\n", __LINE__);
1483 		return -1;
1484 	}
1485 
1486 	memcpy(&rule, &acl_rule, sizeof(rule));
1487 
1488 	/* NULL context */
1489 	result = rte_acl_ipv4vlan_add_rules(NULL, &rule, 1);
1490 	if (result == 0) {
1491 		printf("Line %i: Adding rules with NULL ACL context "
1492 				"should have failed!\n", __LINE__);
1493 		rte_acl_free(acx);
1494 		return -1;
1495 	}
1496 
1497 	/* NULL rule */
1498 	result = rte_acl_ipv4vlan_add_rules(acx, NULL, 1);
1499 	if (result == 0) {
1500 		printf("Line %i: Adding NULL rule to ACL context "
1501 				"should have failed!\n", __LINE__);
1502 		rte_acl_free(acx);
1503 		return -1;
1504 	}
1505 
1506 	/* zero count (should succeed) */
1507 	result = rte_acl_ipv4vlan_add_rules(acx, &rule, 0);
1508 	if (result != 0) {
1509 		printf("Line %i: Adding 0 rules to ACL context failed!\n",
1510 			__LINE__);
1511 		rte_acl_free(acx);
1512 		return -1;
1513 	}
1514 
1515 	/* free ACL context */
1516 	rte_acl_free(acx);
1517 
1518 	/* set wrong rule_size so that adding any rules would fail */
1519 	param.rule_size = RTE_ACL_IPV4VLAN_RULE_SZ + 4;
1520 	acx = rte_acl_create(&param);
1521 	if (acx == NULL) {
1522 		printf("Line %i: ACL context creation failed!\n", __LINE__);
1523 		return -1;
1524 	}
1525 
1526 	/* try adding a rule with size different from context rule_size */
1527 	result = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1528 	if (result == 0) {
1529 		printf("Line %i: Adding an invalid sized rule "
1530 				"should have failed!\n", __LINE__);
1531 		rte_acl_free(acx);
1532 		return -1;
1533 	}
1534 
1535 	/* free ACL context */
1536 	rte_acl_free(acx);
1537 
1538 
1539 	/**
1540 	 * rte_acl_ipv4vlan_build
1541 	 */
1542 
1543 	/* reinitialize context */
1544 	memcpy(&param, &acl_param, sizeof(param));
1545 	acx = rte_acl_create(&param);
1546 	if (acx == NULL) {
1547 		printf("Line %i: ACL context creation failed!\n", __LINE__);
1548 		return -1;
1549 	}
1550 
1551 	/* NULL context */
1552 	result = rte_acl_ipv4vlan_build(NULL, layout, 1);
1553 	if (result == 0) {
1554 		printf("Line %i: Building with NULL context "
1555 				"should have failed!\n", __LINE__);
1556 		rte_acl_free(acx);
1557 		return -1;
1558 	}
1559 
1560 	/* NULL layout */
1561 	result = rte_acl_ipv4vlan_build(acx, NULL, 1);
1562 	if (result == 0) {
1563 		printf("Line %i: Building with NULL layout "
1564 				"should have failed!\n", __LINE__);
1565 		rte_acl_free(acx);
1566 		return -1;
1567 	}
1568 
1569 	/* zero categories (should not fail) */
1570 	result = rte_acl_ipv4vlan_build(acx, layout, 0);
1571 	if (result == 0) {
1572 		printf("Line %i: Building with 0 categories should fail!\n",
1573 			__LINE__);
1574 		rte_acl_free(acx);
1575 		return -1;
1576 	}
1577 
1578 	/* SSE classify test */
1579 
1580 	/* cover zero categories in classify (should not fail) */
1581 	result = rte_acl_classify(acx, NULL, NULL, 0, 0);
1582 	if (result != 0) {
1583 		printf("Line %i: SSE classify with zero categories "
1584 				"failed!\n", __LINE__);
1585 		rte_acl_free(acx);
1586 		return -1;
1587 	}
1588 
1589 	/* cover invalid but positive categories in classify */
1590 	result = rte_acl_classify(acx, NULL, NULL, 0, 3);
1591 	if (result == 0) {
1592 		printf("Line %i: SSE classify with 3 categories "
1593 				"should have failed!\n", __LINE__);
1594 		rte_acl_free(acx);
1595 		return -1;
1596 	}
1597 
1598 	/* scalar classify test */
1599 
1600 	/* cover zero categories in classify (should not fail) */
1601 	result = rte_acl_classify_alg(acx, NULL, NULL, 0, 0,
1602 		RTE_ACL_CLASSIFY_SCALAR);
1603 	if (result != 0) {
1604 		printf("Line %i: Scalar classify with zero categories "
1605 				"failed!\n", __LINE__);
1606 		rte_acl_free(acx);
1607 		return -1;
1608 	}
1609 
1610 	/* cover invalid but positive categories in classify */
1611 	result = rte_acl_classify(acx, NULL, NULL, 0, 3);
1612 	if (result == 0) {
1613 		printf("Line %i: Scalar classify with 3 categories "
1614 				"should have failed!\n", __LINE__);
1615 		rte_acl_free(acx);
1616 		return -1;
1617 	}
1618 
1619 	/* free ACL context */
1620 	rte_acl_free(acx);
1621 
1622 
1623 	/**
1624 	 * make sure void functions don't crash with NULL parameters
1625 	 */
1626 
1627 	rte_acl_free(NULL);
1628 
1629 	rte_acl_dump(NULL);
1630 
1631 	return 0;
1632 }
1633 
1634 /**
1635  * Various tests that don't test much but improve coverage
1636  */
1637 static int
1638 test_misc(void)
1639 {
1640 	struct rte_acl_param param;
1641 	struct rte_acl_ctx *acx;
1642 
1643 	/* create context */
1644 	memcpy(&param, &acl_param, sizeof(param));
1645 
1646 	acx = rte_acl_create(&param);
1647 	if (acx == NULL) {
1648 		printf("Line %i: Error creating ACL context!\n", __LINE__);
1649 		return -1;
1650 	}
1651 
1652 	/* dump context with rules - useful for coverage */
1653 	rte_acl_list_dump();
1654 
1655 	rte_acl_dump(acx);
1656 
1657 	rte_acl_free(acx);
1658 
1659 	return 0;
1660 }
1661 
1662 static int
1663 test_acl(void)
1664 {
1665 	if (test_invalid_parameters() < 0)
1666 		return -1;
1667 	if (test_invalid_rules() < 0)
1668 		return -1;
1669 	if (test_create_find_add() < 0)
1670 		return -1;
1671 	if (test_invalid_layout() < 0)
1672 		return -1;
1673 	if (test_misc() < 0)
1674 		return -1;
1675 	if (test_classify() < 0)
1676 		return -1;
1677 	if (test_build_ports_range() < 0)
1678 		return -1;
1679 	if (test_convert() < 0)
1680 		return -1;
1681 
1682 	return 0;
1683 }
1684 
1685 REGISTER_TEST_COMMAND(acl_autotest, test_acl);
1686