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