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