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