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