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