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