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 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 if (p == NULL) { 70 TABLE_LOG(ERR, "%s: Invalid value for params", __func__); 71 return NULL; 72 } 73 if (p->name == NULL) { 74 TABLE_LOG(ERR, "%s: Invalid value for name", __func__); 75 return NULL; 76 } 77 if (p->n_rules == 0) { 78 TABLE_LOG(ERR, "%s: Invalid value for n_rules", 79 __func__); 80 return NULL; 81 } 82 if ((p->n_rule_fields == 0) || 83 (p->n_rule_fields > RTE_ACL_MAX_FIELDS)) { 84 TABLE_LOG(ERR, "%s: Invalid value for n_rule_fields", 85 __func__); 86 return NULL; 87 } 88 89 entry_size = RTE_ALIGN(entry_size, sizeof(uint64_t)); 90 91 /* Memory allocation */ 92 action_table_size = RTE_CACHE_LINE_ROUNDUP(p->n_rules * entry_size); 93 acl_rule_list_size = 94 RTE_CACHE_LINE_ROUNDUP(p->n_rules * sizeof(struct rte_acl_rule *)); 95 acl_rule_memory_size = RTE_CACHE_LINE_ROUNDUP(p->n_rules * 96 RTE_ACL_RULE_SZ(p->n_rule_fields)); 97 total_size = sizeof(struct rte_table_acl) + action_table_size + 98 acl_rule_list_size + acl_rule_memory_size; 99 100 acl = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, 101 socket_id); 102 if (acl == NULL) { 103 TABLE_LOG(ERR, 104 "%s: Cannot allocate %u bytes for ACL table", 105 __func__, total_size); 106 return NULL; 107 } 108 109 acl->action_table = &acl->memory[0]; 110 acl->acl_rule_list = 111 (struct rte_acl_rule **) &acl->memory[action_table_size]; 112 acl->acl_rule_memory = (uint8_t *) 113 &acl->memory[action_table_size + acl_rule_list_size]; 114 115 /* Initialization of internal fields */ 116 snprintf(acl->name[0], RTE_ACL_NAMESIZE, "%s_a", p->name); 117 snprintf(acl->name[1], RTE_ACL_NAMESIZE, "%s_b", p->name); 118 acl->name_id = 1; 119 120 acl->acl_params.name = acl->name[acl->name_id]; 121 acl->acl_params.socket_id = socket_id; 122 acl->acl_params.rule_size = RTE_ACL_RULE_SZ(p->n_rule_fields); 123 acl->acl_params.max_rule_num = p->n_rules; 124 125 acl->cfg.num_categories = 1; 126 acl->cfg.num_fields = p->n_rule_fields; 127 memcpy(&acl->cfg.defs[0], &p->field_format[0], 128 p->n_rule_fields * sizeof(struct rte_acl_field_def)); 129 130 acl->ctx = NULL; 131 132 acl->n_rules = p->n_rules; 133 acl->entry_size = entry_size; 134 135 return acl; 136 } 137 138 static int 139 rte_table_acl_free(void *table) 140 { 141 struct rte_table_acl *acl = table; 142 143 /* Check input parameters */ 144 if (table == NULL) { 145 TABLE_LOG(ERR, "%s: table parameter is NULL", __func__); 146 return -EINVAL; 147 } 148 149 /* Free previously allocated resources */ 150 rte_acl_free(acl->ctx); 151 152 rte_free(acl); 153 154 return 0; 155 } 156 157 RTE_ACL_RULE_DEF(rte_pipeline_acl_rule, RTE_ACL_MAX_FIELDS); 158 159 static int 160 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 ctx = rte_acl_create(&acl->acl_params); 168 if (ctx == NULL) { 169 TABLE_LOG(ERR, "%s: Cannot create low level ACL table", 170 __func__); 171 return -1; 172 } 173 174 /* Add rules to low level ACL table */ 175 n_rules = 0; 176 for (i = 1; i < acl->n_rules; i++) { 177 if (acl->acl_rule_list[i] != NULL) { 178 status = rte_acl_add_rules(ctx, acl->acl_rule_list[i], 179 1); 180 if (status != 0) { 181 TABLE_LOG(ERR, 182 "%s: Cannot add rule to low level ACL table", 183 __func__); 184 rte_acl_free(ctx); 185 return -1; 186 } 187 188 n_rules++; 189 } 190 } 191 192 if (n_rules == 0) { 193 rte_acl_free(ctx); 194 *acl_ctx = NULL; 195 return 0; 196 } 197 198 /* Build low level ACl table */ 199 status = rte_acl_build(ctx, &acl->cfg); 200 if (status != 0) { 201 TABLE_LOG(ERR, 202 "%s: Cannot build the low level ACL table", 203 __func__); 204 rte_acl_free(ctx); 205 return -1; 206 } 207 208 *acl_ctx = ctx; 209 return 0; 210 } 211 212 static int 213 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 if (table == NULL) { 231 TABLE_LOG(ERR, "%s: table parameter is NULL", __func__); 232 return -EINVAL; 233 } 234 if (key == NULL) { 235 TABLE_LOG(ERR, "%s: key parameter is NULL", __func__); 236 return -EINVAL; 237 } 238 if (entry == NULL) { 239 TABLE_LOG(ERR, "%s: entry parameter is NULL", __func__); 240 return -EINVAL; 241 } 242 if (key_found == NULL) { 243 TABLE_LOG(ERR, "%s: key_found parameter is NULL", 244 __func__); 245 return -EINVAL; 246 } 247 if (entry_ptr == NULL) { 248 TABLE_LOG(ERR, "%s: entry_ptr parameter is NULL", 249 __func__); 250 return -EINVAL; 251 } 252 if (rule->priority > RTE_ACL_MAX_PRIORITY) { 253 TABLE_LOG(ERR, "%s: Priority is too high", __func__); 254 return -EINVAL; 255 } 256 257 /* Setup rule data structure */ 258 memset(&acl_rule, 0, sizeof(acl_rule)); 259 acl_rule.data.category_mask = 1; 260 acl_rule.data.priority = RTE_ACL_MAX_PRIORITY - rule->priority; 261 acl_rule.data.userdata = 0; /* To be set up later */ 262 memcpy(&acl_rule.field[0], 263 &rule->field_value[0], 264 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 for (i = 1; i < acl->n_rules; i++) { 270 if (acl->acl_rule_list[i] == NULL) { 271 if (free_pos_valid == 0) { 272 free_pos = i; 273 free_pos_valid = 1; 274 } 275 276 continue; 277 } 278 279 /* Compare the key fields */ 280 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 if (status == 0) { 286 *key_found = 1; 287 *entry_ptr = &acl->memory[i * acl->entry_size]; 288 memcpy(*entry_ptr, entry, acl->entry_size); 289 290 return 0; 291 } 292 } 293 294 /* Return if max rules */ 295 if (free_pos_valid == 0) { 296 TABLE_LOG(ERR, "%s: Max number of rules reached", 297 __func__); 298 return -ENOSPC; 299 } 300 301 /* Add the new rule to the rule set */ 302 acl_rule.data.userdata = free_pos; 303 rule_location = (struct rte_acl_rule *) 304 &acl->acl_rule_memory[free_pos * acl->acl_params.rule_size]; 305 memcpy(rule_location, &acl_rule, acl->acl_params.rule_size); 306 acl->acl_rule_list[free_pos] = rule_location; 307 308 /* Build low level ACL table */ 309 acl->name_id ^= 1; 310 acl->acl_params.name = acl->name[acl->name_id]; 311 status = rte_table_acl_build(acl, &ctx); 312 if (status != 0) { 313 /* Roll back changes */ 314 acl->acl_rule_list[free_pos] = NULL; 315 acl->name_id ^= 1; 316 317 return -EINVAL; 318 } 319 320 /* Commit changes */ 321 rte_acl_free(acl->ctx); 322 acl->ctx = ctx; 323 *key_found = 0; 324 *entry_ptr = &acl->memory[free_pos * acl->entry_size]; 325 memcpy(*entry_ptr, entry, acl->entry_size); 326 327 return 0; 328 } 329 330 static int 331 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 if (table == NULL) { 347 TABLE_LOG(ERR, "%s: table parameter is NULL", __func__); 348 return -EINVAL; 349 } 350 if (key == NULL) { 351 TABLE_LOG(ERR, "%s: key parameter is NULL", __func__); 352 return -EINVAL; 353 } 354 if (key_found == NULL) { 355 TABLE_LOG(ERR, "%s: key_found parameter is NULL", 356 __func__); 357 return -EINVAL; 358 } 359 360 /* Look for the rule in the table */ 361 pos = 0; 362 pos_valid = 0; 363 for (i = 1; i < acl->n_rules; i++) { 364 if (acl->acl_rule_list[i] != NULL) { 365 /* Compare the key fields */ 366 status = memcmp(&acl->acl_rule_list[i]->field[0], 367 &rule->field_value[0], acl->cfg.num_fields * 368 sizeof(struct rte_acl_field)); 369 370 /* Rule found: remove from table */ 371 if (status == 0) { 372 pos = i; 373 pos_valid = 1; 374 375 deleted_rule = acl->acl_rule_list[i]; 376 acl->acl_rule_list[i] = NULL; 377 } 378 } 379 } 380 381 /* Return if rule not found */ 382 if (pos_valid == 0) { 383 *key_found = 0; 384 return 0; 385 } 386 387 /* Build low level ACL table */ 388 acl->name_id ^= 1; 389 acl->acl_params.name = acl->name[acl->name_id]; 390 status = rte_table_acl_build(acl, &ctx); 391 if (status != 0) { 392 /* Roll back changes */ 393 acl->acl_rule_list[pos] = deleted_rule; 394 acl->name_id ^= 1; 395 396 return -EINVAL; 397 } 398 399 /* Commit changes */ 400 rte_acl_free(acl->ctx); 401 402 acl->ctx = ctx; 403 *key_found = 1; 404 if (entry != NULL) 405 memcpy(entry, &acl->memory[pos * acl->entry_size], 406 acl->entry_size); 407 408 return 0; 409 } 410 411 static int 412 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 { 420 struct rte_table_acl *acl = table; 421 struct rte_acl_ctx *ctx; 422 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 if (table == NULL) { 429 TABLE_LOG(ERR, "%s: table parameter is NULL", __func__); 430 return -EINVAL; 431 } 432 if (keys == NULL) { 433 TABLE_LOG(ERR, "%s: keys parameter is NULL", __func__); 434 return -EINVAL; 435 } 436 if (entries == NULL) { 437 TABLE_LOG(ERR, "%s: entries parameter is NULL", __func__); 438 return -EINVAL; 439 } 440 if (n_keys == 0) { 441 TABLE_LOG(ERR, "%s: 0 rules to add", __func__); 442 return -EINVAL; 443 } 444 if (key_found == NULL) { 445 TABLE_LOG(ERR, "%s: key_found parameter is NULL", 446 __func__); 447 return -EINVAL; 448 } 449 if (entries_ptr == NULL) { 450 TABLE_LOG(ERR, "%s: entries_ptr parameter is NULL", 451 __func__); 452 return -EINVAL; 453 } 454 455 /* Check input parameters in arrays */ 456 for (i = 0; i < n_keys; i++) { 457 struct rte_table_acl_rule_add_params *rule; 458 459 if (keys[i] == NULL) { 460 TABLE_LOG(ERR, "%s: keys[%" PRIu32 "] parameter is NULL", 461 __func__, i); 462 return -EINVAL; 463 } 464 465 if (entries[i] == NULL) { 466 TABLE_LOG(ERR, "%s: entries[%" PRIu32 "] parameter is NULL", 467 __func__, i); 468 return -EINVAL; 469 } 470 471 rule = keys[i]; 472 if (rule->priority > RTE_ACL_MAX_PRIORITY) { 473 TABLE_LOG(ERR, "%s: Priority is too high", __func__); 474 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 for (i = 0; i < n_keys; i++) { 481 struct rte_table_acl_rule_add_params *rule = 482 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 acl_rule.data.category_mask = 1; 490 acl_rule.data.priority = RTE_ACL_MAX_PRIORITY - rule->priority; 491 acl_rule.data.userdata = 0; /* To be set up later */ 492 memcpy(&acl_rule.field[0], 493 &rule->field_value[0], 494 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 for (j = 1; j < acl->n_rules; j++) { 500 if (acl->acl_rule_list[j] == NULL) { 501 if (free_pos_valid == 0) { 502 free_pos = j; 503 free_pos_valid = 1; 504 } 505 506 continue; 507 } 508 509 /* Compare the key fields */ 510 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 if (status == 0) { 516 key_found[i] = 1; 517 entries_ptr[i] = &acl->memory[j * acl->entry_size]; 518 memcpy(entries_ptr[i], entries[i], acl->entry_size); 519 520 break; 521 } 522 } 523 524 /* Key already in the table */ 525 if (key_found[i] != 0) 526 continue; 527 528 /* Maximum number of rules reached */ 529 if (free_pos_valid == 0) { 530 err = 1; 531 break; 532 } 533 534 /* Add the new rule to the rule set */ 535 acl_rule.data.userdata = free_pos; 536 rule_location = (struct rte_acl_rule *) 537 &acl->acl_rule_memory[free_pos * acl->acl_params.rule_size]; 538 memcpy(rule_location, &acl_rule, acl->acl_params.rule_size); 539 acl->acl_rule_list[free_pos] = rule_location; 540 rule_pos[i] = free_pos; 541 build = 1; 542 } 543 544 if (err != 0) { 545 for (i = 0; i < n_keys; i++) { 546 if (rule_pos[i] == 0) 547 continue; 548 549 acl->acl_rule_list[rule_pos[i]] = NULL; 550 } 551 552 return -ENOSPC; 553 } 554 555 if (build == 0) 556 return 0; 557 558 /* Build low level ACL table */ 559 acl->name_id ^= 1; 560 acl->acl_params.name = acl->name[acl->name_id]; 561 status = rte_table_acl_build(acl, &ctx); 562 if (status != 0) { 563 /* Roll back changes */ 564 for (i = 0; i < n_keys; i++) { 565 if (rule_pos[i] == 0) 566 continue; 567 568 acl->acl_rule_list[rule_pos[i]] = NULL; 569 } 570 acl->name_id ^= 1; 571 572 return -EINVAL; 573 } 574 575 /* Commit changes */ 576 rte_acl_free(acl->ctx); 577 acl->ctx = ctx; 578 579 for (i = 0; i < n_keys; i++) { 580 if (rule_pos[i] == 0) 581 continue; 582 583 key_found[i] = 0; 584 entries_ptr[i] = &acl->memory[rule_pos[i] * acl->entry_size]; 585 memcpy(entries_ptr[i], entries[i], acl->entry_size); 586 } 587 588 return 0; 589 } 590 591 static int 592 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 { 599 struct rte_table_acl *acl = table; 600 struct rte_acl_rule *deleted_rules[n_keys]; 601 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 if (table == NULL) { 609 TABLE_LOG(ERR, "%s: table parameter is NULL", __func__); 610 return -EINVAL; 611 } 612 if (keys == NULL) { 613 TABLE_LOG(ERR, "%s: key parameter is NULL", __func__); 614 return -EINVAL; 615 } 616 if (n_keys == 0) { 617 TABLE_LOG(ERR, "%s: 0 rules to delete", __func__); 618 return -EINVAL; 619 } 620 if (key_found == NULL) { 621 TABLE_LOG(ERR, "%s: key_found parameter is NULL", 622 __func__); 623 return -EINVAL; 624 } 625 626 for (i = 0; i < n_keys; i++) { 627 if (keys[i] == NULL) { 628 TABLE_LOG(ERR, "%s: keys[%" PRIu32 "] parameter is NULL", 629 __func__, i); 630 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 for (i = 0; i < n_keys; i++) { 637 struct rte_table_acl_rule_delete_params *rule = 638 keys[i]; 639 uint32_t pos_valid, j; 640 641 /* Look for the rule in the table */ 642 pos_valid = 0; 643 for (j = 1; j < acl->n_rules; j++) { 644 if (acl->acl_rule_list[j] == NULL) 645 continue; 646 647 /* Compare the key fields */ 648 status = memcmp(&acl->acl_rule_list[j]->field[0], 649 &rule->field_value[0], 650 acl->cfg.num_fields * sizeof(struct rte_acl_field)); 651 652 /* Rule found: remove from table */ 653 if (status == 0) { 654 pos_valid = 1; 655 656 deleted_rules[i] = acl->acl_rule_list[j]; 657 acl->acl_rule_list[j] = NULL; 658 rule_pos[i] = j; 659 660 build = 1; 661 } 662 } 663 664 if (pos_valid == 0) { 665 key_found[i] = 0; 666 continue; 667 } 668 } 669 670 /* Return if no changes to acl table */ 671 if (build == 0) { 672 return 0; 673 } 674 675 /* Build low level ACL table */ 676 acl->name_id ^= 1; 677 acl->acl_params.name = acl->name[acl->name_id]; 678 status = rte_table_acl_build(acl, &ctx); 679 if (status != 0) { 680 /* Roll back changes */ 681 for (i = 0; i < n_keys; i++) { 682 if (rule_pos[i] == 0) 683 continue; 684 685 acl->acl_rule_list[rule_pos[i]] = deleted_rules[i]; 686 } 687 688 acl->name_id ^= 1; 689 690 return -EINVAL; 691 } 692 693 /* Commit changes */ 694 rte_acl_free(acl->ctx); 695 696 acl->ctx = ctx; 697 for (i = 0; i < n_keys; i++) { 698 if (rule_pos[i] == 0) 699 continue; 700 701 key_found[i] = 1; 702 if (entries != NULL && entries[i] != NULL) 703 memcpy(entries[i], &acl->memory[rule_pos[i] * acl->entry_size], 704 acl->entry_size); 705 } 706 707 return 0; 708 } 709 710 static int 711 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 for (i = 0, j = 0; i < (uint32_t)(RTE_PORT_IN_BURST_SIZE_MAX - 729 rte_clz64(pkts_mask)); i++) { 730 uint64_t pkt_mask = 1LLU << i; 731 732 if (pkt_mask & pkts_mask) { 733 pkts_data[j] = rte_pktmbuf_mtod(pkts[i], uint8_t *); 734 j++; 735 } 736 } 737 n_pkts = j; 738 739 /* Low-level ACL table lookup */ 740 if (acl->ctx != NULL) 741 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 for (i = 0; i < n_pkts; i++) { 748 uint32_t action_table_pos = results[i]; 749 uint32_t pkt_pos = rte_ctz64(pkts_mask); 750 uint64_t pkt_mask = 1LLU << pkt_pos; 751 752 pkts_mask &= ~pkt_mask; 753 754 if (action_table_pos != 0) { 755 pkts_out_mask |= pkt_mask; 756 entries[pkt_pos] = (void *) 757 &acl->memory[action_table_pos * 758 acl->entry_size]; 759 rte_prefetch0(entries[pkt_pos]); 760 } 761 } 762 763 *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 return 0; 767 } 768 769 static int 770 rte_table_acl_stats_read(void *table, struct rte_table_stats *stats, int clear) 771 { 772 struct rte_table_acl *acl = table; 773 774 if (stats != NULL) 775 memcpy(stats, &acl->stats, sizeof(acl->stats)); 776 777 if (clear) 778 memset(&acl->stats, 0, sizeof(acl->stats)); 779 780 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 }; 793