Imported Upstream version 16.04
[deb_dpdk.git] / lib / librte_table / rte_table_acl.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <string.h>
35 #include <stdio.h>
36
37 #include <rte_common.h>
38 #include <rte_mbuf.h>
39 #include <rte_memory.h>
40 #include <rte_malloc.h>
41 #include <rte_log.h>
42
43 #include "rte_table_acl.h"
44 #include <rte_ether.h>
45
46 #ifdef RTE_TABLE_STATS_COLLECT
47
48 #define RTE_TABLE_ACL_STATS_PKTS_IN_ADD(table, val) \
49         table->stats.n_pkts_in += val
50 #define RTE_TABLE_ACL_STATS_PKTS_LOOKUP_MISS(table, val) \
51         table->stats.n_pkts_lookup_miss += val
52
53 #else
54
55 #define RTE_TABLE_ACL_STATS_PKTS_IN_ADD(table, val)
56 #define RTE_TABLE_ACL_STATS_PKTS_LOOKUP_MISS(table, val)
57
58 #endif
59
60 struct rte_table_acl {
61         struct rte_table_stats stats;
62
63         /* Low-level ACL table */
64         char name[2][RTE_ACL_NAMESIZE];
65         struct rte_acl_param acl_params; /* for creating low level acl table */
66         struct rte_acl_config cfg; /* Holds the field definitions (metadata) */
67         struct rte_acl_ctx *ctx;
68         uint32_t name_id;
69
70         /* Input parameters */
71         uint32_t n_rules;
72         uint32_t entry_size;
73
74         /* Internal tables */
75         uint8_t *action_table;
76         struct rte_acl_rule **acl_rule_list; /* Array of pointers to rules */
77         uint8_t *acl_rule_memory; /* Memory to store the rules */
78
79         /* Memory to store the action table and stack of free entries */
80         uint8_t memory[0] __rte_cache_aligned;
81 };
82
83
84 static void *
85 rte_table_acl_create(
86         void *params,
87         int socket_id,
88         uint32_t entry_size)
89 {
90         struct rte_table_acl_params *p = (struct rte_table_acl_params *) params;
91         struct rte_table_acl *acl;
92         uint32_t action_table_size, acl_rule_list_size, acl_rule_memory_size;
93         uint32_t total_size;
94
95         RTE_BUILD_BUG_ON(((sizeof(struct rte_table_acl) % RTE_CACHE_LINE_SIZE)
96                 != 0));
97
98         /* Check input parameters */
99         if (p == NULL) {
100                 RTE_LOG(ERR, TABLE, "%s: Invalid value for params\n", __func__);
101                 return NULL;
102         }
103         if (p->name == NULL) {
104                 RTE_LOG(ERR, TABLE, "%s: Invalid value for name\n", __func__);
105                 return NULL;
106         }
107         if (p->n_rules == 0) {
108                 RTE_LOG(ERR, TABLE, "%s: Invalid value for n_rules\n",
109                         __func__);
110                 return NULL;
111         }
112         if ((p->n_rule_fields == 0) ||
113             (p->n_rule_fields > RTE_ACL_MAX_FIELDS)) {
114                 RTE_LOG(ERR, TABLE, "%s: Invalid value for n_rule_fields\n",
115                         __func__);
116                 return NULL;
117         }
118
119         entry_size = RTE_ALIGN(entry_size, sizeof(uint64_t));
120
121         /* Memory allocation */
122         action_table_size = RTE_CACHE_LINE_ROUNDUP(p->n_rules * entry_size);
123         acl_rule_list_size =
124                 RTE_CACHE_LINE_ROUNDUP(p->n_rules * sizeof(struct rte_acl_rule *));
125         acl_rule_memory_size = RTE_CACHE_LINE_ROUNDUP(p->n_rules *
126                 RTE_ACL_RULE_SZ(p->n_rule_fields));
127         total_size = sizeof(struct rte_table_acl) + action_table_size +
128                 acl_rule_list_size + acl_rule_memory_size;
129
130         acl = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE,
131                 socket_id);
132         if (acl == NULL) {
133                 RTE_LOG(ERR, TABLE,
134                         "%s: Cannot allocate %u bytes for ACL table\n",
135                         __func__, total_size);
136                 return NULL;
137         }
138
139         acl->action_table = &acl->memory[0];
140         acl->acl_rule_list =
141                 (struct rte_acl_rule **) &acl->memory[action_table_size];
142         acl->acl_rule_memory = (uint8_t *)
143                 &acl->memory[action_table_size + acl_rule_list_size];
144
145         /* Initialization of internal fields */
146         snprintf(acl->name[0], RTE_ACL_NAMESIZE, "%s_a", p->name);
147         snprintf(acl->name[1], RTE_ACL_NAMESIZE, "%s_b", p->name);
148         acl->name_id = 1;
149
150         acl->acl_params.name = acl->name[acl->name_id];
151         acl->acl_params.socket_id = socket_id;
152         acl->acl_params.rule_size = RTE_ACL_RULE_SZ(p->n_rule_fields);
153         acl->acl_params.max_rule_num = p->n_rules;
154
155         acl->cfg.num_categories = 1;
156         acl->cfg.num_fields = p->n_rule_fields;
157         memcpy(&acl->cfg.defs[0], &p->field_format[0],
158                 p->n_rule_fields * sizeof(struct rte_acl_field_def));
159
160         acl->ctx = NULL;
161
162         acl->n_rules = p->n_rules;
163         acl->entry_size = entry_size;
164
165         return acl;
166 }
167
168 static int
169 rte_table_acl_free(void *table)
170 {
171         struct rte_table_acl *acl = (struct rte_table_acl *) table;
172
173         /* Check input parameters */
174         if (table == NULL) {
175                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
176                 return -EINVAL;
177         }
178
179         /* Free previously allocated resources */
180         if (acl->ctx != NULL)
181                 rte_acl_free(acl->ctx);
182
183         rte_free(acl);
184
185         return 0;
186 }
187
188 RTE_ACL_RULE_DEF(rte_pipeline_acl_rule, RTE_ACL_MAX_FIELDS);
189
190 static int
191 rte_table_acl_build(struct rte_table_acl *acl, struct rte_acl_ctx **acl_ctx)
192 {
193         struct rte_acl_ctx *ctx = NULL;
194         uint32_t n_rules, i;
195         int status;
196
197         /* Create low level ACL table */
198         ctx = rte_acl_create(&acl->acl_params);
199         if (ctx == NULL) {
200                 RTE_LOG(ERR, TABLE, "%s: Cannot create low level ACL table\n",
201                         __func__);
202                 return -1;
203         }
204
205         /* Add rules to low level ACL table */
206         n_rules = 0;
207         for (i = 1; i < acl->n_rules; i++) {
208                 if (acl->acl_rule_list[i] != NULL) {
209                         status = rte_acl_add_rules(ctx, acl->acl_rule_list[i],
210                                 1);
211                         if (status != 0) {
212                                 RTE_LOG(ERR, TABLE,
213                                 "%s: Cannot add rule to low level ACL table\n",
214                                         __func__);
215                                 rte_acl_free(ctx);
216                                 return -1;
217                         }
218
219                         n_rules++;
220                 }
221         }
222
223         if (n_rules == 0) {
224                 rte_acl_free(ctx);
225                 *acl_ctx = NULL;
226                 return 0;
227         }
228
229         /* Build low level ACl table */
230         status = rte_acl_build(ctx, &acl->cfg);
231         if (status != 0) {
232                 RTE_LOG(ERR, TABLE,
233                         "%s: Cannot build the low level ACL table\n",
234                         __func__);
235                 rte_acl_free(ctx);
236                 return -1;
237         }
238
239         rte_acl_dump(ctx);
240
241         *acl_ctx = ctx;
242         return 0;
243 }
244
245 static int
246 rte_table_acl_entry_add(
247         void *table,
248         void *key,
249         void *entry,
250         int *key_found,
251         void **entry_ptr)
252 {
253         struct rte_table_acl *acl = (struct rte_table_acl *) table;
254         struct rte_table_acl_rule_add_params *rule =
255                 (struct rte_table_acl_rule_add_params *) key;
256         struct rte_pipeline_acl_rule acl_rule;
257         struct rte_acl_rule *rule_location;
258         struct rte_acl_ctx *ctx;
259         uint32_t free_pos, free_pos_valid, i;
260         int status;
261
262         /* Check input parameters */
263         if (table == NULL) {
264                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
265                 return -EINVAL;
266         }
267         if (key == NULL) {
268                 RTE_LOG(ERR, TABLE, "%s: key parameter is NULL\n", __func__);
269                 return -EINVAL;
270         }
271         if (entry == NULL) {
272                 RTE_LOG(ERR, TABLE, "%s: entry parameter is NULL\n", __func__);
273                 return -EINVAL;
274         }
275         if (key_found == NULL) {
276                 RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
277                         __func__);
278                 return -EINVAL;
279         }
280         if (entry_ptr == NULL) {
281                 RTE_LOG(ERR, TABLE, "%s: entry_ptr parameter is NULL\n",
282                         __func__);
283                 return -EINVAL;
284         }
285         if (rule->priority > RTE_ACL_MAX_PRIORITY) {
286                 RTE_LOG(ERR, TABLE, "%s: Priority is too high\n", __func__);
287                 return -EINVAL;
288         }
289
290         /* Setup rule data structure */
291         memset(&acl_rule, 0, sizeof(acl_rule));
292         acl_rule.data.category_mask = 1;
293         acl_rule.data.priority = RTE_ACL_MAX_PRIORITY - rule->priority;
294         acl_rule.data.userdata = 0; /* To be set up later */
295         memcpy(&acl_rule.field[0],
296                 &rule->field_value[0],
297                 acl->cfg.num_fields * sizeof(struct rte_acl_field));
298
299         /* Look to see if the rule exists already in the table */
300         free_pos = 0;
301         free_pos_valid = 0;
302         for (i = 1; i < acl->n_rules; i++) {
303                 if (acl->acl_rule_list[i] == NULL) {
304                         if (free_pos_valid == 0) {
305                                 free_pos = i;
306                                 free_pos_valid = 1;
307                         }
308
309                         continue;
310                 }
311
312                 /* Compare the key fields */
313                 status = memcmp(&acl->acl_rule_list[i]->field[0],
314                         &rule->field_value[0],
315                         acl->cfg.num_fields * sizeof(struct rte_acl_field));
316
317                 /* Rule found: update data associated with the rule */
318                 if (status == 0) {
319                         *key_found = 1;
320                         *entry_ptr = &acl->memory[i * acl->entry_size];
321                         memcpy(*entry_ptr, entry, acl->entry_size);
322
323                         return 0;
324                 }
325         }
326
327         /* Return if max rules */
328         if (free_pos_valid == 0) {
329                 RTE_LOG(ERR, TABLE, "%s: Max number of rules reached\n",
330                         __func__);
331                 return -ENOSPC;
332         }
333
334         /* Add the new rule to the rule set */
335         acl_rule.data.userdata = free_pos;
336         rule_location = (struct rte_acl_rule *)
337                 &acl->acl_rule_memory[free_pos * acl->acl_params.rule_size];
338         memcpy(rule_location, &acl_rule, acl->acl_params.rule_size);
339         acl->acl_rule_list[free_pos] = rule_location;
340
341         /* Build low level ACL table */
342         acl->name_id ^= 1;
343         acl->acl_params.name = acl->name[acl->name_id];
344         status = rte_table_acl_build(acl, &ctx);
345         if (status != 0) {
346                 /* Roll back changes */
347                 acl->acl_rule_list[free_pos] = NULL;
348                 acl->name_id ^= 1;
349
350                 return -EINVAL;
351         }
352
353         /* Commit changes */
354         if (acl->ctx != NULL)
355                 rte_acl_free(acl->ctx);
356         acl->ctx = ctx;
357         *key_found = 0;
358         *entry_ptr = &acl->memory[free_pos * acl->entry_size];
359         memcpy(*entry_ptr, entry, acl->entry_size);
360
361         return 0;
362 }
363
364 static int
365 rte_table_acl_entry_delete(
366         void *table,
367         void *key,
368         int *key_found,
369         void *entry)
370 {
371         struct rte_table_acl *acl = (struct rte_table_acl *) table;
372         struct rte_table_acl_rule_delete_params *rule =
373                 (struct rte_table_acl_rule_delete_params *) key;
374         struct rte_acl_rule *deleted_rule = NULL;
375         struct rte_acl_ctx *ctx;
376         uint32_t pos, pos_valid, i;
377         int status;
378
379         /* Check input parameters */
380         if (table == NULL) {
381                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
382                 return -EINVAL;
383         }
384         if (key == NULL) {
385                 RTE_LOG(ERR, TABLE, "%s: key parameter is NULL\n", __func__);
386                 return -EINVAL;
387         }
388         if (key_found == NULL) {
389                 RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
390                         __func__);
391                 return -EINVAL;
392         }
393
394         /* Look for the rule in the table */
395         pos = 0;
396         pos_valid = 0;
397         for (i = 1; i < acl->n_rules; i++) {
398                 if (acl->acl_rule_list[i] != NULL) {
399                         /* Compare the key fields */
400                         status = memcmp(&acl->acl_rule_list[i]->field[0],
401                                 &rule->field_value[0], acl->cfg.num_fields *
402                                 sizeof(struct rte_acl_field));
403
404                         /* Rule found: remove from table */
405                         if (status == 0) {
406                                 pos = i;
407                                 pos_valid = 1;
408
409                                 deleted_rule = acl->acl_rule_list[i];
410                                 acl->acl_rule_list[i] = NULL;
411                         }
412                 }
413         }
414
415         /* Return if rule not found */
416         if (pos_valid == 0) {
417                 *key_found = 0;
418                 return 0;
419         }
420
421         /* Build low level ACL table */
422         acl->name_id ^= 1;
423         acl->acl_params.name = acl->name[acl->name_id];
424         status = rte_table_acl_build(acl, &ctx);
425         if (status != 0) {
426                 /* Roll back changes */
427                 acl->acl_rule_list[pos] = deleted_rule;
428                 acl->name_id ^= 1;
429
430                 return -EINVAL;
431         }
432
433         /* Commit changes */
434         if (acl->ctx != NULL)
435                 rte_acl_free(acl->ctx);
436
437         acl->ctx = ctx;
438         *key_found = 1;
439         if (entry != NULL)
440                 memcpy(entry, &acl->memory[pos * acl->entry_size],
441                         acl->entry_size);
442
443         return 0;
444 }
445
446 static int
447 rte_table_acl_entry_add_bulk(
448         void *table,
449         void **keys,
450         void **entries,
451         uint32_t n_keys,
452         int *key_found,
453         void **entries_ptr)
454 {
455         struct rte_table_acl *acl = (struct rte_table_acl *) table;
456         struct rte_acl_ctx *ctx;
457         uint32_t rule_pos[n_keys];
458         uint32_t i;
459         int err = 0, build = 0;
460         int status;
461
462         /* Check input parameters */
463         if (table == NULL) {
464                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
465                 return -EINVAL;
466         }
467         if (keys == NULL) {
468                 RTE_LOG(ERR, TABLE, "%s: keys parameter is NULL\n", __func__);
469                 return -EINVAL;
470         }
471         if (entries == NULL) {
472                 RTE_LOG(ERR, TABLE, "%s: entries parameter is NULL\n", __func__);
473                 return -EINVAL;
474         }
475         if (n_keys == 0) {
476                 RTE_LOG(ERR, TABLE, "%s: 0 rules to add\n", __func__);
477                 return -EINVAL;
478         }
479         if (key_found == NULL) {
480                 RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
481                         __func__);
482                 return -EINVAL;
483         }
484         if (entries_ptr == NULL) {
485                 RTE_LOG(ERR, TABLE, "%s: entries_ptr parameter is NULL\n",
486                         __func__);
487                 return -EINVAL;
488         }
489
490         /* Check input parameters in arrays */
491         for (i = 0; i < n_keys; i++) {
492                 struct rte_table_acl_rule_add_params *rule;
493
494                 if (keys[i] == NULL) {
495                         RTE_LOG(ERR, TABLE, "%s: keys[%" PRIu32 "] parameter is NULL\n",
496                                         __func__, i);
497                         return -EINVAL;
498                 }
499
500                 if (entries[i] == NULL) {
501                         RTE_LOG(ERR, TABLE, "%s: entries[%" PRIu32 "] parameter is NULL\n",
502                                         __func__, i);
503                         return -EINVAL;
504                 }
505
506                 if (entries_ptr[i] == NULL) {
507                         RTE_LOG(ERR, TABLE, "%s: entries_ptr[%" PRIu32 "] parameter is NULL\n",
508                                         __func__, i);
509                         return -EINVAL;
510                 }
511
512                 rule = (struct rte_table_acl_rule_add_params *) keys[i];
513                 if (rule->priority > RTE_ACL_MAX_PRIORITY) {
514                         RTE_LOG(ERR, TABLE, "%s: Priority is too high\n", __func__);
515                         return -EINVAL;
516                 }
517         }
518
519         memset(rule_pos, 0, n_keys * sizeof(uint32_t));
520         memset(key_found, 0, n_keys * sizeof(int));
521         for (i = 0; i < n_keys; i++) {
522                 struct rte_table_acl_rule_add_params *rule =
523                                 (struct rte_table_acl_rule_add_params *) keys[i];
524                 struct rte_pipeline_acl_rule acl_rule;
525                 struct rte_acl_rule *rule_location;
526                 uint32_t free_pos, free_pos_valid, j;
527
528                 /* Setup rule data structure */
529                 memset(&acl_rule, 0, sizeof(acl_rule));
530                 acl_rule.data.category_mask = 1;
531                 acl_rule.data.priority = RTE_ACL_MAX_PRIORITY - rule->priority;
532                 acl_rule.data.userdata = 0; /* To be set up later */
533                 memcpy(&acl_rule.field[0],
534                         &rule->field_value[0],
535                         acl->cfg.num_fields * sizeof(struct rte_acl_field));
536
537                 /* Look to see if the rule exists already in the table */
538                 free_pos = 0;
539                 free_pos_valid = 0;
540                 for (j = 1; j < acl->n_rules; j++) {
541                         if (acl->acl_rule_list[j] == NULL) {
542                                 if (free_pos_valid == 0) {
543                                         free_pos = j;
544                                         free_pos_valid = 1;
545                                 }
546
547                                 continue;
548                         }
549
550                         /* Compare the key fields */
551                         status = memcmp(&acl->acl_rule_list[j]->field[0],
552                                 &rule->field_value[0],
553                                 acl->cfg.num_fields * sizeof(struct rte_acl_field));
554
555                         /* Rule found: update data associated with the rule */
556                         if (status == 0) {
557                                 key_found[i] = 1;
558                                 entries_ptr[i] = &acl->memory[j * acl->entry_size];
559                                 memcpy(entries_ptr[i], entries[i], acl->entry_size);
560
561                                 break;
562                         }
563                 }
564
565                 /* Key already in the table */
566                 if (key_found[i] != 0)
567                         continue;
568
569                 /* Maximum number of rules reached */
570                 if (free_pos_valid == 0) {
571                         err = 1;
572                         break;
573                 }
574
575                 /* Add the new rule to the rule set */
576                 acl_rule.data.userdata = free_pos;
577                 rule_location = (struct rte_acl_rule *)
578                         &acl->acl_rule_memory[free_pos * acl->acl_params.rule_size];
579                 memcpy(rule_location, &acl_rule, acl->acl_params.rule_size);
580                 acl->acl_rule_list[free_pos] = rule_location;
581                 rule_pos[i] = free_pos;
582                 build = 1;
583         }
584
585         if (err != 0) {
586                 for (i = 0; i < n_keys; i++) {
587                         if (rule_pos[i] == 0)
588                                 continue;
589
590                         acl->acl_rule_list[rule_pos[i]] = NULL;
591                 }
592
593                 return -ENOSPC;
594         }
595
596         if (build == 0)
597                 return 0;
598
599         /* Build low level ACL table */
600         acl->name_id ^= 1;
601         acl->acl_params.name = acl->name[acl->name_id];
602         status = rte_table_acl_build(acl, &ctx);
603         if (status != 0) {
604                 /* Roll back changes */
605                 for (i = 0; i < n_keys; i++) {
606                         if (rule_pos[i] == 0)
607                                 continue;
608
609                         acl->acl_rule_list[rule_pos[i]] = NULL;
610                 }
611                 acl->name_id ^= 1;
612
613                 return -EINVAL;
614         }
615
616         /* Commit changes */
617         if (acl->ctx != NULL)
618                 rte_acl_free(acl->ctx);
619         acl->ctx = ctx;
620
621         for (i = 0; i < n_keys; i++) {
622                 if (rule_pos[i] == 0)
623                         continue;
624
625                 key_found[i] = 0;
626                 entries_ptr[i] = &acl->memory[rule_pos[i] * acl->entry_size];
627                 memcpy(entries_ptr[i], entries[i], acl->entry_size);
628         }
629
630         return 0;
631 }
632
633 static int
634 rte_table_acl_entry_delete_bulk(
635         void *table,
636         void **keys,
637         uint32_t n_keys,
638         int *key_found,
639         void **entries)
640 {
641         struct rte_table_acl *acl = (struct rte_table_acl *) table;
642         struct rte_acl_rule *deleted_rules[n_keys];
643         uint32_t rule_pos[n_keys];
644         struct rte_acl_ctx *ctx;
645         uint32_t i;
646         int status;
647         int build = 0;
648
649         /* Check input parameters */
650         if (table == NULL) {
651                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
652                 return -EINVAL;
653         }
654         if (keys == NULL) {
655                 RTE_LOG(ERR, TABLE, "%s: key parameter is NULL\n", __func__);
656                 return -EINVAL;
657         }
658         if (n_keys == 0) {
659                 RTE_LOG(ERR, TABLE, "%s: 0 rules to delete\n", __func__);
660                 return -EINVAL;
661         }
662         if (key_found == NULL) {
663                 RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
664                         __func__);
665                 return -EINVAL;
666         }
667
668         for (i = 0; i < n_keys; i++) {
669                 if (keys[i] == NULL) {
670                         RTE_LOG(ERR, TABLE, "%s: keys[%" PRIu32 "] parameter is NULL\n",
671                                         __func__, i);
672                         return -EINVAL;
673                 }
674         }
675
676         memset(deleted_rules, 0, n_keys * sizeof(struct rte_acl_rule *));
677         memset(rule_pos, 0, n_keys * sizeof(uint32_t));
678         for (i = 0; i < n_keys; i++) {
679                 struct rte_table_acl_rule_delete_params *rule =
680                         (struct rte_table_acl_rule_delete_params *) keys[i];
681                 uint32_t pos_valid, j;
682
683                 /* Look for the rule in the table */
684                 pos_valid = 0;
685                 for (j = 1; j < acl->n_rules; j++) {
686                         if (acl->acl_rule_list[j] == NULL)
687                                 continue;
688
689                         /* Compare the key fields */
690                         status = memcmp(&acl->acl_rule_list[j]->field[0],
691                                         &rule->field_value[0],
692                                         acl->cfg.num_fields * sizeof(struct rte_acl_field));
693
694                         /* Rule found: remove from table */
695                         if (status == 0) {
696                                 pos_valid = 1;
697
698                                 deleted_rules[i] = acl->acl_rule_list[j];
699                                 acl->acl_rule_list[j] = NULL;
700                                 rule_pos[i] = j;
701
702                                 build = 1;
703                         }
704                 }
705
706                 if (pos_valid == 0) {
707                         key_found[i] = 0;
708                         continue;
709                 }
710         }
711
712         /* Return if no changes to acl table */
713         if (build == 0) {
714                 return 0;
715         }
716
717         /* Build low level ACL table */
718         acl->name_id ^= 1;
719         acl->acl_params.name = acl->name[acl->name_id];
720         status = rte_table_acl_build(acl, &ctx);
721         if (status != 0) {
722                 /* Roll back changes */
723                 for (i = 0; i < n_keys; i++) {
724                         if (rule_pos[i] == 0)
725                                 continue;
726
727                         acl->acl_rule_list[rule_pos[i]] = deleted_rules[i];
728                 }
729
730                 acl->name_id ^= 1;
731
732                 return -EINVAL;
733         }
734
735         /* Commit changes */
736         if (acl->ctx != NULL)
737                 rte_acl_free(acl->ctx);
738
739         acl->ctx = ctx;
740         for (i = 0; i < n_keys; i++) {
741                 if (rule_pos[i] == 0)
742                         continue;
743
744                 key_found[i] = 1;
745                 if (entries != NULL && entries[i] != NULL)
746                         memcpy(entries[i], &acl->memory[rule_pos[i] * acl->entry_size],
747                                         acl->entry_size);
748         }
749
750         return 0;
751 }
752
753 static int
754 rte_table_acl_lookup(
755         void *table,
756         struct rte_mbuf **pkts,
757         uint64_t pkts_mask,
758         uint64_t *lookup_hit_mask,
759         void **entries)
760 {
761         struct rte_table_acl *acl = (struct rte_table_acl *) table;
762         const uint8_t *pkts_data[RTE_PORT_IN_BURST_SIZE_MAX];
763         uint32_t results[RTE_PORT_IN_BURST_SIZE_MAX];
764         uint64_t pkts_out_mask;
765         uint32_t n_pkts, i, j;
766
767         __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
768         RTE_TABLE_ACL_STATS_PKTS_IN_ADD(acl, n_pkts_in);
769
770         /* Input conversion */
771         for (i = 0, j = 0; i < (uint32_t)(RTE_PORT_IN_BURST_SIZE_MAX -
772                 __builtin_clzll(pkts_mask)); i++) {
773                 uint64_t pkt_mask = 1LLU << i;
774
775                 if (pkt_mask & pkts_mask) {
776                         pkts_data[j] = rte_pktmbuf_mtod(pkts[i], uint8_t *);
777                         j++;
778                 }
779         }
780         n_pkts = j;
781
782         /* Low-level ACL table lookup */
783         if (acl->ctx != NULL)
784                 rte_acl_classify(acl->ctx, pkts_data, results, n_pkts, 1);
785         else
786                 n_pkts = 0;
787
788         /* Output conversion */
789         pkts_out_mask = 0;
790         for (i = 0; i < n_pkts; i++) {
791                 uint32_t action_table_pos = results[i];
792                 uint32_t pkt_pos = __builtin_ctzll(pkts_mask);
793                 uint64_t pkt_mask = 1LLU << pkt_pos;
794
795                 pkts_mask &= ~pkt_mask;
796
797                 if (action_table_pos != RTE_ACL_INVALID_USERDATA) {
798                         pkts_out_mask |= pkt_mask;
799                         entries[pkt_pos] = (void *)
800                                 &acl->memory[action_table_pos *
801                                 acl->entry_size];
802                         rte_prefetch0(entries[pkt_pos]);
803                 }
804         }
805
806         *lookup_hit_mask = pkts_out_mask;
807         RTE_TABLE_ACL_STATS_PKTS_LOOKUP_MISS(acl, n_pkts_in - __builtin_popcountll(pkts_out_mask));
808
809         return 0;
810 }
811
812 static int
813 rte_table_acl_stats_read(void *table, struct rte_table_stats *stats, int clear)
814 {
815         struct rte_table_acl *acl = (struct rte_table_acl *) table;
816
817         if (stats != NULL)
818                 memcpy(stats, &acl->stats, sizeof(acl->stats));
819
820         if (clear)
821                 memset(&acl->stats, 0, sizeof(acl->stats));
822
823         return 0;
824 }
825
826 struct rte_table_ops rte_table_acl_ops = {
827         .f_create = rte_table_acl_create,
828         .f_free = rte_table_acl_free,
829         .f_add = rte_table_acl_entry_add,
830         .f_delete = rte_table_acl_entry_delete,
831         .f_add_bulk = rte_table_acl_entry_add_bulk,
832         .f_delete_bulk = rte_table_acl_entry_delete_bulk,
833         .f_lookup = rte_table_acl_lookup,
834         .f_stats = rte_table_acl_stats_read,
835 };