ip_frag: add IPv4 options fragment
[dpdk.git] / app / test / test_acl.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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);