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