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