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