Imported Upstream version 16.07-rc1
[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         *acl_ctx = ctx;
240         return 0;
241 }
242
243 static int
244 rte_table_acl_entry_add(
245         void *table,
246         void *key,
247         void *entry,
248         int *key_found,
249         void **entry_ptr)
250 {
251         struct rte_table_acl *acl = (struct rte_table_acl *) table;
252         struct rte_table_acl_rule_add_params *rule =
253                 (struct rte_table_acl_rule_add_params *) key;
254         struct rte_pipeline_acl_rule acl_rule;
255         struct rte_acl_rule *rule_location;
256         struct rte_acl_ctx *ctx;
257         uint32_t free_pos, free_pos_valid, i;
258         int status;
259
260         /* Check input parameters */
261         if (table == NULL) {
262                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
263                 return -EINVAL;
264         }
265         if (key == NULL) {
266                 RTE_LOG(ERR, TABLE, "%s: key parameter is NULL\n", __func__);
267                 return -EINVAL;
268         }
269         if (entry == NULL) {
270                 RTE_LOG(ERR, TABLE, "%s: entry parameter is NULL\n", __func__);
271                 return -EINVAL;
272         }
273         if (key_found == NULL) {
274                 RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
275                         __func__);
276                 return -EINVAL;
277         }
278         if (entry_ptr == NULL) {
279                 RTE_LOG(ERR, TABLE, "%s: entry_ptr parameter is NULL\n",
280                         __func__);
281                 return -EINVAL;
282         }
283         if (rule->priority > RTE_ACL_MAX_PRIORITY) {
284                 RTE_LOG(ERR, TABLE, "%s: Priority is too high\n", __func__);
285                 return -EINVAL;
286         }
287
288         /* Setup rule data structure */
289         memset(&acl_rule, 0, sizeof(acl_rule));
290         acl_rule.data.category_mask = 1;
291         acl_rule.data.priority = RTE_ACL_MAX_PRIORITY - rule->priority;
292         acl_rule.data.userdata = 0; /* To be set up later */
293         memcpy(&acl_rule.field[0],
294                 &rule->field_value[0],
295                 acl->cfg.num_fields * sizeof(struct rte_acl_field));
296
297         /* Look to see if the rule exists already in the table */
298         free_pos = 0;
299         free_pos_valid = 0;
300         for (i = 1; i < acl->n_rules; i++) {
301                 if (acl->acl_rule_list[i] == NULL) {
302                         if (free_pos_valid == 0) {
303                                 free_pos = i;
304                                 free_pos_valid = 1;
305                         }
306
307                         continue;
308                 }
309
310                 /* Compare the key fields */
311                 status = memcmp(&acl->acl_rule_list[i]->field[0],
312                         &rule->field_value[0],
313                         acl->cfg.num_fields * sizeof(struct rte_acl_field));
314
315                 /* Rule found: update data associated with the rule */
316                 if (status == 0) {
317                         *key_found = 1;
318                         *entry_ptr = &acl->memory[i * acl->entry_size];
319                         memcpy(*entry_ptr, entry, acl->entry_size);
320
321                         return 0;
322                 }
323         }
324
325         /* Return if max rules */
326         if (free_pos_valid == 0) {
327                 RTE_LOG(ERR, TABLE, "%s: Max number of rules reached\n",
328                         __func__);
329                 return -ENOSPC;
330         }
331
332         /* Add the new rule to the rule set */
333         acl_rule.data.userdata = free_pos;
334         rule_location = (struct rte_acl_rule *)
335                 &acl->acl_rule_memory[free_pos * acl->acl_params.rule_size];
336         memcpy(rule_location, &acl_rule, acl->acl_params.rule_size);
337         acl->acl_rule_list[free_pos] = rule_location;
338
339         /* Build low level ACL table */
340         acl->name_id ^= 1;
341         acl->acl_params.name = acl->name[acl->name_id];
342         status = rte_table_acl_build(acl, &ctx);
343         if (status != 0) {
344                 /* Roll back changes */
345                 acl->acl_rule_list[free_pos] = NULL;
346                 acl->name_id ^= 1;
347
348                 return -EINVAL;
349         }
350
351         /* Commit changes */
352         if (acl->ctx != NULL)
353                 rte_acl_free(acl->ctx);
354         acl->ctx = ctx;
355         *key_found = 0;
356         *entry_ptr = &acl->memory[free_pos * acl->entry_size];
357         memcpy(*entry_ptr, entry, acl->entry_size);
358
359         return 0;
360 }
361
362 static int
363 rte_table_acl_entry_delete(
364         void *table,
365         void *key,
366         int *key_found,
367         void *entry)
368 {
369         struct rte_table_acl *acl = (struct rte_table_acl *) table;
370         struct rte_table_acl_rule_delete_params *rule =
371                 (struct rte_table_acl_rule_delete_params *) key;
372         struct rte_acl_rule *deleted_rule = NULL;
373         struct rte_acl_ctx *ctx;
374         uint32_t pos, pos_valid, i;
375         int status;
376
377         /* Check input parameters */
378         if (table == NULL) {
379                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
380                 return -EINVAL;
381         }
382         if (key == NULL) {
383                 RTE_LOG(ERR, TABLE, "%s: key parameter is NULL\n", __func__);
384                 return -EINVAL;
385         }
386         if (key_found == NULL) {
387                 RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
388                         __func__);
389                 return -EINVAL;
390         }
391
392         /* Look for the rule in the table */
393         pos = 0;
394         pos_valid = 0;
395         for (i = 1; i < acl->n_rules; i++) {
396                 if (acl->acl_rule_list[i] != NULL) {
397                         /* Compare the key fields */
398                         status = memcmp(&acl->acl_rule_list[i]->field[0],
399                                 &rule->field_value[0], acl->cfg.num_fields *
400                                 sizeof(struct rte_acl_field));
401
402                         /* Rule found: remove from table */
403                         if (status == 0) {
404                                 pos = i;
405                                 pos_valid = 1;
406
407                                 deleted_rule = acl->acl_rule_list[i];
408                                 acl->acl_rule_list[i] = NULL;
409                         }
410                 }
411         }
412
413         /* Return if rule not found */
414         if (pos_valid == 0) {
415                 *key_found = 0;
416                 return 0;
417         }
418
419         /* Build low level ACL table */
420         acl->name_id ^= 1;
421         acl->acl_params.name = acl->name[acl->name_id];
422         status = rte_table_acl_build(acl, &ctx);
423         if (status != 0) {
424                 /* Roll back changes */
425                 acl->acl_rule_list[pos] = deleted_rule;
426                 acl->name_id ^= 1;
427
428                 return -EINVAL;
429         }
430
431         /* Commit changes */
432         if (acl->ctx != NULL)
433                 rte_acl_free(acl->ctx);
434
435         acl->ctx = ctx;
436         *key_found = 1;
437         if (entry != NULL)
438                 memcpy(entry, &acl->memory[pos * acl->entry_size],
439                         acl->entry_size);
440
441         return 0;
442 }
443
444 static int
445 rte_table_acl_entry_add_bulk(
446         void *table,
447         void **keys,
448         void **entries,
449         uint32_t n_keys,
450         int *key_found,
451         void **entries_ptr)
452 {
453         struct rte_table_acl *acl = (struct rte_table_acl *) table;
454         struct rte_acl_ctx *ctx;
455         uint32_t rule_pos[n_keys];
456         uint32_t i;
457         int err = 0, build = 0;
458         int status;
459
460         /* Check input parameters */
461         if (table == NULL) {
462                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
463                 return -EINVAL;
464         }
465         if (keys == NULL) {
466                 RTE_LOG(ERR, TABLE, "%s: keys parameter is NULL\n", __func__);
467                 return -EINVAL;
468         }
469         if (entries == NULL) {
470                 RTE_LOG(ERR, TABLE, "%s: entries parameter is NULL\n", __func__);
471                 return -EINVAL;
472         }
473         if (n_keys == 0) {
474                 RTE_LOG(ERR, TABLE, "%s: 0 rules to add\n", __func__);
475                 return -EINVAL;
476         }
477         if (key_found == NULL) {
478                 RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
479                         __func__);
480                 return -EINVAL;
481         }
482         if (entries_ptr == NULL) {
483                 RTE_LOG(ERR, TABLE, "%s: entries_ptr parameter is NULL\n",
484                         __func__);
485                 return -EINVAL;
486         }
487
488         /* Check input parameters in arrays */
489         for (i = 0; i < n_keys; i++) {
490                 struct rte_table_acl_rule_add_params *rule;
491
492                 if (keys[i] == NULL) {
493                         RTE_LOG(ERR, TABLE, "%s: keys[%" PRIu32 "] parameter is NULL\n",
494                                         __func__, i);
495                         return -EINVAL;
496                 }
497
498                 if (entries[i] == NULL) {
499                         RTE_LOG(ERR, TABLE, "%s: entries[%" PRIu32 "] parameter is NULL\n",
500                                         __func__, i);
501                         return -EINVAL;
502                 }
503
504                 if (entries_ptr[i] == NULL) {
505                         RTE_LOG(ERR, TABLE, "%s: entries_ptr[%" PRIu32 "] parameter is NULL\n",
506                                         __func__, i);
507                         return -EINVAL;
508                 }
509
510                 rule = (struct rte_table_acl_rule_add_params *) keys[i];
511                 if (rule->priority > RTE_ACL_MAX_PRIORITY) {
512                         RTE_LOG(ERR, TABLE, "%s: Priority is too high\n", __func__);
513                         return -EINVAL;
514                 }
515         }
516
517         memset(rule_pos, 0, n_keys * sizeof(uint32_t));
518         memset(key_found, 0, n_keys * sizeof(int));
519         for (i = 0; i < n_keys; i++) {
520                 struct rte_table_acl_rule_add_params *rule =
521                                 (struct rte_table_acl_rule_add_params *) keys[i];
522                 struct rte_pipeline_acl_rule acl_rule;
523                 struct rte_acl_rule *rule_location;
524                 uint32_t free_pos, free_pos_valid, j;
525
526                 /* Setup rule data structure */
527                 memset(&acl_rule, 0, sizeof(acl_rule));
528                 acl_rule.data.category_mask = 1;
529                 acl_rule.data.priority = RTE_ACL_MAX_PRIORITY - rule->priority;
530                 acl_rule.data.userdata = 0; /* To be set up later */
531                 memcpy(&acl_rule.field[0],
532                         &rule->field_value[0],
533                         acl->cfg.num_fields * sizeof(struct rte_acl_field));
534
535                 /* Look to see if the rule exists already in the table */
536                 free_pos = 0;
537                 free_pos_valid = 0;
538                 for (j = 1; j < acl->n_rules; j++) {
539                         if (acl->acl_rule_list[j] == NULL) {
540                                 if (free_pos_valid == 0) {
541                                         free_pos = j;
542                                         free_pos_valid = 1;
543                                 }
544
545                                 continue;
546                         }
547
548                         /* Compare the key fields */
549                         status = memcmp(&acl->acl_rule_list[j]->field[0],
550                                 &rule->field_value[0],
551                                 acl->cfg.num_fields * sizeof(struct rte_acl_field));
552
553                         /* Rule found: update data associated with the rule */
554                         if (status == 0) {
555                                 key_found[i] = 1;
556                                 entries_ptr[i] = &acl->memory[j * acl->entry_size];
557                                 memcpy(entries_ptr[i], entries[i], acl->entry_size);
558
559                                 break;
560                         }
561                 }
562
563                 /* Key already in the table */
564                 if (key_found[i] != 0)
565                         continue;
566
567                 /* Maximum number of rules reached */
568                 if (free_pos_valid == 0) {
569                         err = 1;
570                         break;
571                 }
572
573                 /* Add the new rule to the rule set */
574                 acl_rule.data.userdata = free_pos;
575                 rule_location = (struct rte_acl_rule *)
576                         &acl->acl_rule_memory[free_pos * acl->acl_params.rule_size];
577                 memcpy(rule_location, &acl_rule, acl->acl_params.rule_size);
578                 acl->acl_rule_list[free_pos] = rule_location;
579                 rule_pos[i] = free_pos;
580                 build = 1;
581         }
582
583         if (err != 0) {
584                 for (i = 0; i < n_keys; i++) {
585                         if (rule_pos[i] == 0)
586                                 continue;
587
588                         acl->acl_rule_list[rule_pos[i]] = NULL;
589                 }
590
591                 return -ENOSPC;
592         }
593
594         if (build == 0)
595                 return 0;
596
597         /* Build low level ACL table */
598         acl->name_id ^= 1;
599         acl->acl_params.name = acl->name[acl->name_id];
600         status = rte_table_acl_build(acl, &ctx);
601         if (status != 0) {
602                 /* Roll back changes */
603                 for (i = 0; i < n_keys; i++) {
604                         if (rule_pos[i] == 0)
605                                 continue;
606
607                         acl->acl_rule_list[rule_pos[i]] = NULL;
608                 }
609                 acl->name_id ^= 1;
610
611                 return -EINVAL;
612         }
613
614         /* Commit changes */
615         if (acl->ctx != NULL)
616                 rte_acl_free(acl->ctx);
617         acl->ctx = ctx;
618
619         for (i = 0; i < n_keys; i++) {
620                 if (rule_pos[i] == 0)
621                         continue;
622
623                 key_found[i] = 0;
624                 entries_ptr[i] = &acl->memory[rule_pos[i] * acl->entry_size];
625                 memcpy(entries_ptr[i], entries[i], acl->entry_size);
626         }
627
628         return 0;
629 }
630
631 static int
632 rte_table_acl_entry_delete_bulk(
633         void *table,
634         void **keys,
635         uint32_t n_keys,
636         int *key_found,
637         void **entries)
638 {
639         struct rte_table_acl *acl = (struct rte_table_acl *) table;
640         struct rte_acl_rule *deleted_rules[n_keys];
641         uint32_t rule_pos[n_keys];
642         struct rte_acl_ctx *ctx;
643         uint32_t i;
644         int status;
645         int build = 0;
646
647         /* Check input parameters */
648         if (table == NULL) {
649                 RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__);
650                 return -EINVAL;
651         }
652         if (keys == NULL) {
653                 RTE_LOG(ERR, TABLE, "%s: key parameter is NULL\n", __func__);
654                 return -EINVAL;
655         }
656         if (n_keys == 0) {
657                 RTE_LOG(ERR, TABLE, "%s: 0 rules to delete\n", __func__);
658                 return -EINVAL;
659         }
660         if (key_found == NULL) {
661                 RTE_LOG(ERR, TABLE, "%s: key_found parameter is NULL\n",
662                         __func__);
663                 return -EINVAL;
664         }
665
666         for (i = 0; i < n_keys; i++) {
667                 if (keys[i] == NULL) {
668                         RTE_LOG(ERR, TABLE, "%s: keys[%" PRIu32 "] parameter is NULL\n",
669                                         __func__, i);
670                         return -EINVAL;
671                 }
672         }
673
674         memset(deleted_rules, 0, n_keys * sizeof(struct rte_acl_rule *));
675         memset(rule_pos, 0, n_keys * sizeof(uint32_t));
676         for (i = 0; i < n_keys; i++) {
677                 struct rte_table_acl_rule_delete_params *rule =
678                         (struct rte_table_acl_rule_delete_params *) keys[i];
679                 uint32_t pos_valid, j;
680
681                 /* Look for the rule in the table */
682                 pos_valid = 0;
683                 for (j = 1; j < acl->n_rules; j++) {
684                         if (acl->acl_rule_list[j] == NULL)
685                                 continue;
686
687                         /* Compare the key fields */
688                         status = memcmp(&acl->acl_rule_list[j]->field[0],
689                                         &rule->field_value[0],
690                                         acl->cfg.num_fields * sizeof(struct rte_acl_field));
691
692                         /* Rule found: remove from table */
693                         if (status == 0) {
694                                 pos_valid = 1;
695
696                                 deleted_rules[i] = acl->acl_rule_list[j];
697                                 acl->acl_rule_list[j] = NULL;
698                                 rule_pos[i] = j;
699
700                                 build = 1;
701                         }
702                 }
703
704                 if (pos_valid == 0) {
705                         key_found[i] = 0;
706                         continue;
707                 }
708         }
709
710         /* Return if no changes to acl table */
711         if (build == 0) {
712                 return 0;
713         }
714
715         /* Build low level ACL table */
716         acl->name_id ^= 1;
717         acl->acl_params.name = acl->name[acl->name_id];
718         status = rte_table_acl_build(acl, &ctx);
719         if (status != 0) {
720                 /* Roll back changes */
721                 for (i = 0; i < n_keys; i++) {
722                         if (rule_pos[i] == 0)
723                                 continue;
724
725                         acl->acl_rule_list[rule_pos[i]] = deleted_rules[i];
726                 }
727
728                 acl->name_id ^= 1;
729
730                 return -EINVAL;
731         }
732
733         /* Commit changes */
734         if (acl->ctx != NULL)
735                 rte_acl_free(acl->ctx);
736
737         acl->ctx = ctx;
738         for (i = 0; i < n_keys; i++) {
739                 if (rule_pos[i] == 0)
740                         continue;
741
742                 key_found[i] = 1;
743                 if (entries != NULL && entries[i] != NULL)
744                         memcpy(entries[i], &acl->memory[rule_pos[i] * acl->entry_size],
745                                         acl->entry_size);
746         }
747
748         return 0;
749 }
750
751 static int
752 rte_table_acl_lookup(
753         void *table,
754         struct rte_mbuf **pkts,
755         uint64_t pkts_mask,
756         uint64_t *lookup_hit_mask,
757         void **entries)
758 {
759         struct rte_table_acl *acl = (struct rte_table_acl *) table;
760         const uint8_t *pkts_data[RTE_PORT_IN_BURST_SIZE_MAX];
761         uint32_t results[RTE_PORT_IN_BURST_SIZE_MAX];
762         uint64_t pkts_out_mask;
763         uint32_t n_pkts, i, j;
764
765         __rte_unused uint32_t n_pkts_in = __builtin_popcountll(pkts_mask);
766         RTE_TABLE_ACL_STATS_PKTS_IN_ADD(acl, n_pkts_in);
767
768         /* Input conversion */
769         for (i = 0, j = 0; i < (uint32_t)(RTE_PORT_IN_BURST_SIZE_MAX -
770                 __builtin_clzll(pkts_mask)); i++) {
771                 uint64_t pkt_mask = 1LLU << i;
772
773                 if (pkt_mask & pkts_mask) {
774                         pkts_data[j] = rte_pktmbuf_mtod(pkts[i], uint8_t *);
775                         j++;
776                 }
777         }
778         n_pkts = j;
779
780         /* Low-level ACL table lookup */
781         if (acl->ctx != NULL)
782                 rte_acl_classify(acl->ctx, pkts_data, results, n_pkts, 1);
783         else
784                 n_pkts = 0;
785
786         /* Output conversion */
787         pkts_out_mask = 0;
788         for (i = 0; i < n_pkts; i++) {
789                 uint32_t action_table_pos = results[i];
790                 uint32_t pkt_pos = __builtin_ctzll(pkts_mask);
791                 uint64_t pkt_mask = 1LLU << pkt_pos;
792
793                 pkts_mask &= ~pkt_mask;
794
795                 if (action_table_pos != RTE_ACL_INVALID_USERDATA) {
796                         pkts_out_mask |= pkt_mask;
797                         entries[pkt_pos] = (void *)
798                                 &acl->memory[action_table_pos *
799                                 acl->entry_size];
800                         rte_prefetch0(entries[pkt_pos]);
801                 }
802         }
803
804         *lookup_hit_mask = pkts_out_mask;
805         RTE_TABLE_ACL_STATS_PKTS_LOOKUP_MISS(acl, n_pkts_in - __builtin_popcountll(pkts_out_mask));
806
807         return 0;
808 }
809
810 static int
811 rte_table_acl_stats_read(void *table, struct rte_table_stats *stats, int clear)
812 {
813         struct rte_table_acl *acl = (struct rte_table_acl *) table;
814
815         if (stats != NULL)
816                 memcpy(stats, &acl->stats, sizeof(acl->stats));
817
818         if (clear)
819                 memset(&acl->stats, 0, sizeof(acl->stats));
820
821         return 0;
822 }
823
824 struct rte_table_ops rte_table_acl_ops = {
825         .f_create = rte_table_acl_create,
826         .f_free = rte_table_acl_free,
827         .f_add = rte_table_acl_entry_add,
828         .f_delete = rte_table_acl_entry_delete,
829         .f_add_bulk = rte_table_acl_entry_add_bulk,
830         .f_delete_bulk = rte_table_acl_entry_delete_bulk,
831         .f_lookup = rte_table_acl_lookup,
832         .f_stats = rte_table_acl_stats_read,
833 };