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