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