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