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