xref: /dpdk/app/test/test_acl.c (revision 3c60274c)
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 			RTE_LOG(ERR, ACL, "%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 		if (tmp)
1175 			rte_acl_free(tmp);
1176 		goto err;
1177 	}
1178 
1179 	param.name = acx2_name;
1180 	tmp = rte_acl_create(&param);
1181 	if (tmp != acx2) {
1182 		printf("Line %i: Creating context with existing "
1183 			"name test 2 failed!\n",
1184 			__LINE__);
1185 		if (tmp)
1186 			rte_acl_free(tmp);
1187 		goto err;
1188 	}
1189 
1190 	/* try to find existing ACL contexts */
1191 	tmp = rte_acl_find_existing(acx_name);
1192 	if (tmp != acx) {
1193 		printf("Line %i: Finding %s failed!\n", __LINE__, acx_name);
1194 		if (tmp)
1195 			rte_acl_free(tmp);
1196 		goto err;
1197 	}
1198 
1199 	tmp = rte_acl_find_existing(acx2_name);
1200 	if (tmp != acx2) {
1201 		printf("Line %i: Finding %s failed!\n", __LINE__, acx2_name);
1202 		if (tmp)
1203 			rte_acl_free(tmp);
1204 		goto err;
1205 	}
1206 
1207 	/* try to find non-existing context */
1208 	tmp = rte_acl_find_existing("invalid");
1209 	if (tmp != NULL) {
1210 		printf("Line %i: Non-existent ACL context found!\n", __LINE__);
1211 		goto err;
1212 	}
1213 
1214 	/* free context */
1215 	rte_acl_free(acx);
1216 
1217 
1218 	/* create valid (but severely limited) acx */
1219 	memcpy(&param, &acl_param, sizeof(param));
1220 	param.max_rule_num = LEN;
1221 
1222 	acx = rte_acl_create(&param);
1223 	if (acx == NULL) {
1224 		printf("Line %i: Error creating %s!\n", __LINE__, param.name);
1225 		goto err;
1226 	}
1227 
1228 	/* create dummy acl */
1229 	for (i = 0; i < LEN; i++) {
1230 		memcpy(&rules[i], &acl_rule,
1231 			sizeof(struct rte_acl_ipv4vlan_rule));
1232 		/* skip zero */
1233 		rules[i].data.userdata = i + 1;
1234 		/* one rule per category */
1235 		rules[i].data.category_mask = 1 << i;
1236 	}
1237 
1238 	/* try filling up the context */
1239 	ret = rte_acl_ipv4vlan_add_rules(acx, rules, LEN);
1240 	if (ret != 0) {
1241 		printf("Line %i: Adding %i rules to ACL context failed!\n",
1242 				__LINE__, LEN);
1243 		goto err;
1244 	}
1245 
1246 	/* try adding to a (supposedly) full context */
1247 	ret = rte_acl_ipv4vlan_add_rules(acx, rules, 1);
1248 	if (ret == 0) {
1249 		printf("Line %i: Adding rules to full ACL context should"
1250 				"have failed!\n", __LINE__);
1251 		goto err;
1252 	}
1253 
1254 	/* try building the context */
1255 	ret = rte_acl_ipv4vlan_build(acx, layout, RTE_ACL_MAX_CATEGORIES);
1256 	if (ret != 0) {
1257 		printf("Line %i: Building ACL context failed!\n", __LINE__);
1258 		goto err;
1259 	}
1260 
1261 	rte_acl_free(acx);
1262 	rte_acl_free(acx2);
1263 
1264 	return 0;
1265 err:
1266 	rte_acl_free(acx);
1267 	rte_acl_free(acx2);
1268 	return -1;
1269 }
1270 
1271 /*
1272  * test various invalid rules
1273  */
1274 static int
test_invalid_rules(void)1275 test_invalid_rules(void)
1276 {
1277 	struct rte_acl_ctx *acx;
1278 	int ret;
1279 
1280 	struct rte_acl_ipv4vlan_rule rule;
1281 
1282 	acx = rte_acl_create(&acl_param);
1283 	if (acx == NULL) {
1284 		printf("Line %i: Error creating ACL context!\n", __LINE__);
1285 		return -1;
1286 	}
1287 
1288 	/* test inverted high/low source and destination ports.
1289 	 * originally, there was a problem with memory consumption when using
1290 	 * such rules.
1291 	 */
1292 	/* create dummy acl */
1293 	memcpy(&rule, &acl_rule, sizeof(struct rte_acl_ipv4vlan_rule));
1294 	rule.data.userdata = 1;
1295 	rule.dst_port_low = 0xfff0;
1296 	rule.dst_port_high = 0x0010;
1297 
1298 	/* add rules to context and try to build it */
1299 	ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1300 	if (ret == 0) {
1301 		printf("Line %i: Adding rules to ACL context "
1302 				"should have failed!\n", __LINE__);
1303 		goto err;
1304 	}
1305 
1306 	rule.dst_port_low = 0x0;
1307 	rule.dst_port_high = 0xffff;
1308 	rule.src_port_low = 0xfff0;
1309 	rule.src_port_high = 0x0010;
1310 
1311 	/* add rules to context and try to build it */
1312 	ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1313 	if (ret == 0) {
1314 		printf("Line %i: Adding rules to ACL context "
1315 				"should have failed!\n", __LINE__);
1316 		goto err;
1317 	}
1318 
1319 	rule.dst_port_low = 0x0;
1320 	rule.dst_port_high = 0xffff;
1321 	rule.src_port_low = 0x0;
1322 	rule.src_port_high = 0xffff;
1323 
1324 	rule.dst_mask_len = 33;
1325 
1326 	/* add rules to context and try to build it */
1327 	ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1328 	if (ret == 0) {
1329 		printf("Line %i: Adding rules to ACL context "
1330 				"should have failed!\n", __LINE__);
1331 		goto err;
1332 	}
1333 
1334 	rule.dst_mask_len = 0;
1335 	rule.src_mask_len = 33;
1336 
1337 	/* add rules to context and try to build it */
1338 	ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1339 	if (ret == 0) {
1340 		printf("Line %i: Adding rules to ACL context "
1341 				"should have failed!\n", __LINE__);
1342 		goto err;
1343 	}
1344 
1345 	rte_acl_free(acx);
1346 
1347 	return 0;
1348 
1349 err:
1350 	rte_acl_free(acx);
1351 
1352 	return -1;
1353 }
1354 
1355 /*
1356  * test functions by passing invalid or
1357  * non-workable parameters.
1358  *
1359  * we do very limited testing of classify functions here
1360  * because those are performance-critical and
1361  * thus don't do much parameter checking.
1362  */
1363 static int
test_invalid_parameters(void)1364 test_invalid_parameters(void)
1365 {
1366 	struct rte_acl_param param;
1367 	struct rte_acl_ctx *acx;
1368 	struct rte_acl_ipv4vlan_rule rule;
1369 	int result;
1370 
1371 	uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0};
1372 
1373 
1374 	/**
1375 	 * rte_ac_create()
1376 	 */
1377 
1378 	/* NULL param */
1379 	acx = rte_acl_create(NULL);
1380 	if (acx != NULL) {
1381 		printf("Line %i: ACL context creation with NULL param "
1382 				"should have failed!\n", __LINE__);
1383 		rte_acl_free(acx);
1384 		return -1;
1385 	}
1386 
1387 	/* zero rule size */
1388 	memcpy(&param, &acl_param, sizeof(param));
1389 	param.rule_size = 0;
1390 
1391 	acx = rte_acl_create(&param);
1392 	if (acx == NULL) {
1393 		printf("Line %i: ACL context creation with zero rule len "
1394 				"failed!\n", __LINE__);
1395 		return -1;
1396 	} else
1397 		rte_acl_free(acx);
1398 
1399 	/* zero max rule num */
1400 	memcpy(&param, &acl_param, sizeof(param));
1401 	param.max_rule_num = 0;
1402 
1403 	acx = rte_acl_create(&param);
1404 	if (acx == NULL) {
1405 		printf("Line %i: ACL context creation with zero rule num "
1406 				"failed!\n", __LINE__);
1407 		return -1;
1408 	} else
1409 		rte_acl_free(acx);
1410 
1411 	if (rte_eal_has_hugepages()) {
1412 		/* invalid NUMA node */
1413 		memcpy(&param, &acl_param, sizeof(param));
1414 		param.socket_id = RTE_MAX_NUMA_NODES + 1;
1415 
1416 		acx = rte_acl_create(&param);
1417 		if (acx != NULL) {
1418 			printf("Line %i: ACL context creation with invalid "
1419 					"NUMA should have failed!\n", __LINE__);
1420 			rte_acl_free(acx);
1421 			return -1;
1422 		}
1423 	}
1424 
1425 	/* NULL name */
1426 	memcpy(&param, &acl_param, sizeof(param));
1427 	param.name = NULL;
1428 
1429 	acx = rte_acl_create(&param);
1430 	if (acx != NULL) {
1431 		printf("Line %i: ACL context creation with NULL name "
1432 				"should have failed!\n", __LINE__);
1433 		rte_acl_free(acx);
1434 		return -1;
1435 	}
1436 
1437 	/**
1438 	 * rte_acl_find_existing
1439 	 */
1440 
1441 	acx = rte_acl_find_existing(NULL);
1442 	if (acx != NULL) {
1443 		printf("Line %i: NULL ACL context found!\n", __LINE__);
1444 		rte_acl_free(acx);
1445 		return -1;
1446 	}
1447 
1448 	/**
1449 	 * rte_acl_ipv4vlan_add_rules
1450 	 */
1451 
1452 	/* initialize everything */
1453 	memcpy(&param, &acl_param, sizeof(param));
1454 	acx = rte_acl_create(&param);
1455 	if (acx == NULL) {
1456 		printf("Line %i: ACL context creation failed!\n", __LINE__);
1457 		return -1;
1458 	}
1459 
1460 	memcpy(&rule, &acl_rule, sizeof(rule));
1461 
1462 	/* NULL context */
1463 	result = rte_acl_ipv4vlan_add_rules(NULL, &rule, 1);
1464 	if (result == 0) {
1465 		printf("Line %i: Adding rules with NULL ACL context "
1466 				"should have failed!\n", __LINE__);
1467 		rte_acl_free(acx);
1468 		return -1;
1469 	}
1470 
1471 	/* NULL rule */
1472 	result = rte_acl_ipv4vlan_add_rules(acx, NULL, 1);
1473 	if (result == 0) {
1474 		printf("Line %i: Adding NULL rule to ACL context "
1475 				"should have failed!\n", __LINE__);
1476 		rte_acl_free(acx);
1477 		return -1;
1478 	}
1479 
1480 	/* zero count (should succeed) */
1481 	result = rte_acl_ipv4vlan_add_rules(acx, &rule, 0);
1482 	if (result != 0) {
1483 		printf("Line %i: Adding 0 rules to ACL context failed!\n",
1484 			__LINE__);
1485 		rte_acl_free(acx);
1486 		return -1;
1487 	}
1488 
1489 	/* free ACL context */
1490 	rte_acl_free(acx);
1491 
1492 
1493 	/**
1494 	 * rte_acl_ipv4vlan_build
1495 	 */
1496 
1497 	/* reinitialize context */
1498 	memcpy(&param, &acl_param, sizeof(param));
1499 	acx = rte_acl_create(&param);
1500 	if (acx == NULL) {
1501 		printf("Line %i: ACL context creation failed!\n", __LINE__);
1502 		return -1;
1503 	}
1504 
1505 	/* NULL context */
1506 	result = rte_acl_ipv4vlan_build(NULL, layout, 1);
1507 	if (result == 0) {
1508 		printf("Line %i: Building with NULL context "
1509 				"should have failed!\n", __LINE__);
1510 		rte_acl_free(acx);
1511 		return -1;
1512 	}
1513 
1514 	/* NULL layout */
1515 	result = rte_acl_ipv4vlan_build(acx, NULL, 1);
1516 	if (result == 0) {
1517 		printf("Line %i: Building with NULL layout "
1518 				"should have failed!\n", __LINE__);
1519 		rte_acl_free(acx);
1520 		return -1;
1521 	}
1522 
1523 	/* zero categories (should not fail) */
1524 	result = rte_acl_ipv4vlan_build(acx, layout, 0);
1525 	if (result == 0) {
1526 		printf("Line %i: Building with 0 categories should fail!\n",
1527 			__LINE__);
1528 		rte_acl_free(acx);
1529 		return -1;
1530 	}
1531 
1532 	/* SSE classify test */
1533 
1534 	/* cover zero categories in classify (should not fail) */
1535 	result = rte_acl_classify(acx, NULL, NULL, 0, 0);
1536 	if (result != 0) {
1537 		printf("Line %i: SSE classify with zero categories "
1538 				"failed!\n", __LINE__);
1539 		rte_acl_free(acx);
1540 		return -1;
1541 	}
1542 
1543 	/* cover invalid but positive categories in classify */
1544 	result = rte_acl_classify(acx, NULL, NULL, 0, 3);
1545 	if (result == 0) {
1546 		printf("Line %i: SSE classify with 3 categories "
1547 				"should have failed!\n", __LINE__);
1548 		rte_acl_free(acx);
1549 		return -1;
1550 	}
1551 
1552 	/* scalar classify test */
1553 
1554 	/* cover zero categories in classify (should not fail) */
1555 	result = rte_acl_classify_alg(acx, NULL, NULL, 0, 0,
1556 		RTE_ACL_CLASSIFY_SCALAR);
1557 	if (result != 0) {
1558 		printf("Line %i: Scalar classify with zero categories "
1559 				"failed!\n", __LINE__);
1560 		rte_acl_free(acx);
1561 		return -1;
1562 	}
1563 
1564 	/* cover invalid but positive categories in classify */
1565 	result = rte_acl_classify(acx, NULL, NULL, 0, 3);
1566 	if (result == 0) {
1567 		printf("Line %i: Scalar classify with 3 categories "
1568 				"should have failed!\n", __LINE__);
1569 		rte_acl_free(acx);
1570 		return -1;
1571 	}
1572 
1573 	/* free ACL context */
1574 	rte_acl_free(acx);
1575 
1576 
1577 	/**
1578 	 * make sure void functions don't crash with NULL parameters
1579 	 */
1580 
1581 	rte_acl_free(NULL);
1582 
1583 	rte_acl_dump(NULL);
1584 
1585 	return 0;
1586 }
1587 
1588 /**
1589  * Various tests that don't test much but improve coverage
1590  */
1591 static int
test_misc(void)1592 test_misc(void)
1593 {
1594 	struct rte_acl_param param;
1595 	struct rte_acl_ctx *acx;
1596 
1597 	/* create context */
1598 	memcpy(&param, &acl_param, sizeof(param));
1599 
1600 	acx = rte_acl_create(&param);
1601 	if (acx == NULL) {
1602 		printf("Line %i: Error creating ACL context!\n", __LINE__);
1603 		return -1;
1604 	}
1605 
1606 	/* dump context with rules - useful for coverage */
1607 	rte_acl_list_dump();
1608 
1609 	rte_acl_dump(acx);
1610 
1611 	rte_acl_free(acx);
1612 
1613 	return 0;
1614 }
1615 
1616 static uint32_t
get_u32_range_max(void)1617 get_u32_range_max(void)
1618 {
1619 	uint32_t i, max;
1620 
1621 	max = 0;
1622 	for (i = 0; i != RTE_DIM(acl_u32_range_test_rules); i++)
1623 		max = RTE_MAX(max, acl_u32_range_test_rules[i].src_mask_len);
1624 	return max;
1625 }
1626 
1627 static uint32_t
get_u32_range_min(void)1628 get_u32_range_min(void)
1629 {
1630 	uint32_t i, min;
1631 
1632 	min = UINT32_MAX;
1633 	for (i = 0; i != RTE_DIM(acl_u32_range_test_rules); i++)
1634 		min = RTE_MIN(min, acl_u32_range_test_rules[i].src_addr);
1635 	return min;
1636 }
1637 
1638 static const struct rte_acl_ipv4vlan_rule *
find_u32_range_rule(uint32_t val)1639 find_u32_range_rule(uint32_t val)
1640 {
1641 	uint32_t i;
1642 
1643 	for (i = 0; i != RTE_DIM(acl_u32_range_test_rules); i++) {
1644 		if (val >= acl_u32_range_test_rules[i].src_addr &&
1645 				val <= acl_u32_range_test_rules[i].src_mask_len)
1646 			return acl_u32_range_test_rules + i;
1647 	}
1648 	return NULL;
1649 }
1650 
1651 static void
fill_u32_range_data(struct ipv4_7tuple tdata[],uint32_t start,uint32_t num)1652 fill_u32_range_data(struct ipv4_7tuple tdata[], uint32_t start, uint32_t num)
1653 {
1654 	uint32_t i;
1655 	const struct rte_acl_ipv4vlan_rule *r;
1656 
1657 	for (i = 0; i != num; i++) {
1658 		tdata[i].ip_src = start + i;
1659 		r = find_u32_range_rule(start + i);
1660 		if (r != NULL)
1661 			tdata[i].allow = r->data.userdata;
1662 	}
1663 }
1664 
1665 static int
test_u32_range(void)1666 test_u32_range(void)
1667 {
1668 	int32_t rc;
1669 	uint32_t i, k, max, min;
1670 	struct rte_acl_ctx *acx;
1671 	struct acl_ipv4vlan_rule r;
1672 	struct ipv4_7tuple test_data[64];
1673 
1674 	acx = rte_acl_create(&acl_param);
1675 	if (acx == NULL) {
1676 		printf("%s#%i: Error creating ACL context!\n",
1677 			__func__, __LINE__);
1678 		return -1;
1679 	}
1680 
1681 	for (i = 0; i != RTE_DIM(acl_u32_range_test_rules); i++) {
1682 		convert_rule(&acl_u32_range_test_rules[i], &r);
1683 		rc = rte_acl_add_rules(acx, (struct rte_acl_rule *)&r, 1);
1684 		if (rc != 0) {
1685 			printf("%s#%i: Adding rule to ACL context "
1686 				"failed with error code: %d\n",
1687 				__func__, __LINE__, rc);
1688 			rte_acl_free(acx);
1689 			return rc;
1690 		}
1691 	}
1692 
1693 	rc = build_convert_rules(acx, convert_config_2, 0);
1694 	if (rc != 0) {
1695 		printf("%s#%i Error @ build_convert_rules!\n",
1696 			__func__, __LINE__);
1697 		rte_acl_free(acx);
1698 		return rc;
1699 	}
1700 
1701 	max = get_u32_range_max();
1702 	min = get_u32_range_min();
1703 
1704 	max = RTE_MAX(max, max + 1);
1705 	min = RTE_MIN(min, min - 1);
1706 
1707 	printf("%s#%d starting range test from %u to %u\n",
1708 		__func__, __LINE__, min, max);
1709 
1710 	for (i = min; i <= max; i += k) {
1711 
1712 		k = RTE_MIN(max - i + 1, RTE_DIM(test_data));
1713 
1714 		memset(test_data, 0, sizeof(test_data));
1715 		fill_u32_range_data(test_data, i, k);
1716 
1717 		rc = test_classify_run(acx, test_data, k);
1718 		if (rc != 0) {
1719 			printf("%s#%d failed at [%u, %u) interval\n",
1720 				__func__, __LINE__, i, i + k);
1721 			break;
1722 		}
1723 	}
1724 
1725 	rte_acl_free(acx);
1726 	return rc;
1727 }
1728 
1729 static int
test_acl(void)1730 test_acl(void)
1731 {
1732 	if (test_invalid_parameters() < 0)
1733 		return -1;
1734 	if (test_invalid_rules() < 0)
1735 		return -1;
1736 	if (test_create_find_add() < 0)
1737 		return -1;
1738 	if (test_invalid_layout() < 0)
1739 		return -1;
1740 	if (test_misc() < 0)
1741 		return -1;
1742 	if (test_classify() < 0)
1743 		return -1;
1744 	if (test_build_ports_range() < 0)
1745 		return -1;
1746 	if (test_convert() < 0)
1747 		return -1;
1748 	if (test_u32_range() < 0)
1749 		return -1;
1750 
1751 	return 0;
1752 }
1753 
1754 #endif /* !RTE_EXEC_ENV_WINDOWS */
1755 
1756 REGISTER_TEST_COMMAND(acl_autotest, test_acl);
1757