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