1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 #include <errno.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <stdio.h> 8 #include <sys/queue.h> 9 #include <unistd.h> 10 11 #include <rte_common.h> 12 #include <rte_byteorder.h> 13 #include <rte_tailq.h> 14 #include <rte_eal_memconfig.h> 15 16 #include <rte_swx_table_selector.h> 17 18 #include "rte_swx_ctl.h" 19 20 #define CHECK(condition, err_code) \ 21 do { \ 22 if (!(condition)) \ 23 return -(err_code); \ 24 } while (0) 25 26 #define ntoh64(x) rte_be_to_cpu_64(x) 27 #define hton64(x) rte_cpu_to_be_64(x) 28 29 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN 30 #define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits))) 31 #define field_hton(val, n_bits) (hton64((val) << (64 - n_bits))) 32 #else 33 #define field_ntoh(val, n_bits) (val) 34 #define field_hton(val, n_bits) (val) 35 #endif 36 37 struct action { 38 struct rte_swx_ctl_action_info info; 39 struct rte_swx_ctl_action_arg_info *args; 40 uint32_t data_size; 41 }; 42 43 struct table { 44 struct rte_swx_ctl_table_info info; 45 struct rte_swx_ctl_table_match_field_info *mf; 46 47 /* Match field with the smallest offset. */ 48 struct rte_swx_ctl_table_match_field_info *mf_first; 49 50 /* Match field with the biggest offset. */ 51 struct rte_swx_ctl_table_match_field_info *mf_last; 52 53 struct rte_swx_ctl_table_action_info *actions; 54 struct rte_swx_table_ops ops; 55 struct rte_swx_table_params params; 56 57 /* Set of "stable" keys: these keys are currently part of the table; 58 * these keys will be preserved with no action data changes after the 59 * next commit. 60 */ 61 struct rte_swx_table_entry_list entries; 62 63 /* Set of new keys: these keys are currently NOT part of the table; 64 * these keys will be added to the table on the next commit, if 65 * the commit operation is successful. 66 */ 67 struct rte_swx_table_entry_list pending_add; 68 69 /* Set of keys to be modified: these keys are currently part of the 70 * table; these keys are still going to be part of the table after the 71 * next commit, but their action data will be modified if the commit 72 * operation is successful. The modify0 list contains the keys with the 73 * current action data, the modify1 list contains the keys with the 74 * modified action data. 75 */ 76 struct rte_swx_table_entry_list pending_modify0; 77 struct rte_swx_table_entry_list pending_modify1; 78 79 /* Set of keys to be deleted: these keys are currently part of the 80 * table; these keys are to be deleted from the table on the next 81 * commit, if the commit operation is successful. 82 */ 83 struct rte_swx_table_entry_list pending_delete; 84 85 /* The pending default action: this is NOT the current default action; 86 * this will be the new default action after the next commit, if the 87 * next commit operation is successful. 88 */ 89 struct rte_swx_table_entry *pending_default; 90 91 int is_stub; 92 uint32_t n_add; 93 uint32_t n_modify; 94 uint32_t n_delete; 95 }; 96 97 struct selector { 98 /* Selector table info. */ 99 struct rte_swx_ctl_selector_info info; 100 101 /* group_id field. */ 102 struct rte_swx_ctl_table_match_field_info group_id_field; 103 104 /* selector fields. */ 105 struct rte_swx_ctl_table_match_field_info *selector_fields; 106 107 /* member_id field. */ 108 struct rte_swx_ctl_table_match_field_info member_id_field; 109 110 /* Current selector table. Array of info.n_groups_max elements.*/ 111 struct rte_swx_table_selector_group **groups; 112 113 /* Pending selector table subject to the next commit. Array of info.n_groups_max elements. 114 */ 115 struct rte_swx_table_selector_group **pending_groups; 116 117 /* Valid flag per group. Array of n_groups_max elements. */ 118 int *groups_added; 119 120 /* Pending delete flag per group. Group deletion is subject to the next commit. Array of 121 * info.n_groups_max elements. 122 */ 123 int *groups_pending_delete; 124 125 /* Params. */ 126 struct rte_swx_table_selector_params params; 127 }; 128 129 struct learner { 130 struct rte_swx_ctl_learner_info info; 131 struct rte_swx_ctl_table_match_field_info *mf; 132 struct rte_swx_ctl_table_action_info *actions; 133 uint32_t action_data_size; 134 135 /* The pending default action: this is NOT the current default action; 136 * this will be the new default action after the next commit, if the 137 * next commit operation is successful. 138 */ 139 struct rte_swx_table_entry *pending_default; 140 }; 141 142 struct rte_swx_ctl_pipeline { 143 struct rte_swx_ctl_pipeline_info info; 144 struct rte_swx_pipeline *p; 145 struct action *actions; 146 struct table *tables; 147 struct selector *selectors; 148 struct learner *learners; 149 struct rte_swx_table_state *ts; 150 struct rte_swx_table_state *ts_next; 151 int numa_node; 152 }; 153 154 static struct action * 155 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name) 156 { 157 uint32_t i; 158 159 for (i = 0; i < ctl->info.n_actions; i++) { 160 struct action *a = &ctl->actions[i]; 161 162 if (!strcmp(action_name, a->info.name)) 163 return a; 164 } 165 166 return NULL; 167 } 168 169 static void 170 action_free(struct rte_swx_ctl_pipeline *ctl) 171 { 172 uint32_t i; 173 174 if (!ctl->actions) 175 return; 176 177 for (i = 0; i < ctl->info.n_actions; i++) { 178 struct action *action = &ctl->actions[i]; 179 180 free(action->args); 181 } 182 183 free(ctl->actions); 184 ctl->actions = NULL; 185 } 186 187 static struct table * 188 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name) 189 { 190 uint32_t i; 191 192 for (i = 0; i < ctl->info.n_tables; i++) { 193 struct table *table = &ctl->tables[i]; 194 195 if (!strcmp(table_name, table->info.name)) 196 return table; 197 } 198 199 return NULL; 200 } 201 202 static int 203 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 204 { 205 struct table *table = &ctl->tables[table_id]; 206 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL; 207 uint8_t *key_mask = NULL; 208 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD; 209 uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i; 210 211 if (table->info.n_match_fields) { 212 uint32_t n_match_fields_em = 0, i; 213 214 /* Find first (smallest offset) and last (biggest offset) match fields. */ 215 first = &table->mf[0]; 216 last = &table->mf[0]; 217 218 for (i = 1; i < table->info.n_match_fields; i++) { 219 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i]; 220 221 if (f->offset < first->offset) 222 first = f; 223 224 if (f->offset > last->offset) 225 last = f; 226 } 227 228 /* match_type. */ 229 for (i = 0; i < table->info.n_match_fields; i++) { 230 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i]; 231 232 if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT) 233 n_match_fields_em++; 234 } 235 236 if (n_match_fields_em == table->info.n_match_fields) 237 match_type = RTE_SWX_TABLE_MATCH_EXACT; 238 239 /* key_offset. */ 240 key_offset = first->offset / 8; 241 242 /* key_size. */ 243 key_size = (last->offset + last->n_bits - first->offset) / 8; 244 245 /* key_mask. */ 246 key_mask = calloc(1, key_size); 247 CHECK(key_mask, ENOMEM); 248 249 for (i = 0; i < table->info.n_match_fields; i++) { 250 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i]; 251 uint32_t start; 252 size_t size; 253 254 start = (f->offset - first->offset) / 8; 255 size = f->n_bits / 8; 256 257 memset(&key_mask[start], 0xFF, size); 258 } 259 } 260 261 /* action_data_size. */ 262 for (i = 0; i < table->info.n_actions; i++) { 263 uint32_t action_id = table->actions[i].action_id; 264 struct action *a = &ctl->actions[action_id]; 265 266 if (a->data_size > action_data_size) 267 action_data_size = a->data_size; 268 } 269 270 /* Fill in. */ 271 table->params.match_type = match_type; 272 table->params.key_size = key_size; 273 table->params.key_offset = key_offset; 274 table->params.key_mask0 = key_mask; 275 table->params.action_data_size = action_data_size; 276 table->params.hash_func = table->info.hash_func; 277 table->params.n_keys_max = table->info.size; 278 279 table->mf_first = first; 280 table->mf_last = last; 281 282 return 0; 283 } 284 285 static void 286 table_entry_free(struct rte_swx_table_entry *entry) 287 { 288 if (!entry) 289 return; 290 291 free(entry->key); 292 free(entry->key_mask); 293 free(entry->action_data); 294 free(entry); 295 } 296 297 static struct rte_swx_table_entry * 298 table_entry_alloc(struct table *table) 299 { 300 struct rte_swx_table_entry *entry; 301 302 entry = calloc(1, sizeof(struct rte_swx_table_entry)); 303 if (!entry) 304 goto error; 305 306 /* key, key_mask. */ 307 if (!table->is_stub) { 308 entry->key = calloc(1, table->params.key_size); 309 if (!entry->key) 310 goto error; 311 312 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) { 313 entry->key_mask = calloc(1, table->params.key_size); 314 if (!entry->key_mask) 315 goto error; 316 } 317 } 318 319 /* action_data. */ 320 if (table->params.action_data_size) { 321 entry->action_data = calloc(1, table->params.action_data_size); 322 if (!entry->action_data) 323 goto error; 324 } 325 326 return entry; 327 328 error: 329 table_entry_free(entry); 330 return NULL; 331 } 332 333 static int 334 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry) 335 { 336 uint8_t *key_mask0 = table->params.key_mask0; 337 uint32_t key_size = table->params.key_size, i; 338 339 if (!entry->key_mask) 340 return 0; 341 342 for (i = 0; i < key_size; i++) { 343 uint8_t km0 = key_mask0[i]; 344 uint8_t km = entry->key_mask[i]; 345 346 if ((km & km0) != km0) 347 return -EINVAL; 348 } 349 350 return 0; 351 } 352 353 static int 354 table_entry_check(struct rte_swx_ctl_pipeline *ctl, 355 uint32_t table_id, 356 struct rte_swx_table_entry *entry, 357 int key_check, 358 int data_check) 359 { 360 struct table *table = &ctl->tables[table_id]; 361 int status; 362 363 CHECK(entry, EINVAL); 364 365 if (key_check && !table->is_stub) { 366 /* key. */ 367 CHECK(entry->key, EINVAL); 368 369 /* key_mask. */ 370 if (table->params.match_type == RTE_SWX_TABLE_MATCH_EXACT) { 371 status = table_entry_key_check_em(table, entry); 372 if (status) 373 return status; 374 } 375 } 376 377 if (data_check) { 378 struct action *a; 379 struct rte_swx_ctl_table_action_info *tai; 380 uint32_t i; 381 382 /* action_id. */ 383 for (i = 0; i < table->info.n_actions; i++) { 384 tai = &table->actions[i]; 385 386 if (entry->action_id == tai->action_id) 387 break; 388 } 389 390 CHECK(i < table->info.n_actions, EINVAL); 391 392 /* action_data. */ 393 a = &ctl->actions[entry->action_id]; 394 CHECK(!(a->data_size && !entry->action_data), EINVAL); 395 396 /* When both key_check and data_check are true, we are interested in both the entry 397 * key and data, which means the operation is _regular_ table entry add. 398 */ 399 if (key_check && !tai->action_is_for_table_entries) 400 return -EINVAL; 401 402 /* When key_check is false while data_check is true, we are only interested in the 403 * entry data, which means the operation is _default_ table entry add. 404 */ 405 if (!key_check && !tai->action_is_for_default_entry) 406 return -EINVAL; 407 } 408 409 return 0; 410 } 411 412 static struct rte_swx_table_entry * 413 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl, 414 uint32_t table_id, 415 struct rte_swx_table_entry *entry, 416 int key_duplicate, 417 int data_duplicate) 418 { 419 struct table *table = &ctl->tables[table_id]; 420 struct rte_swx_table_entry *new_entry = NULL; 421 422 if (!entry) 423 goto error; 424 425 new_entry = calloc(1, sizeof(struct rte_swx_table_entry)); 426 if (!new_entry) 427 goto error; 428 429 if (key_duplicate && !table->is_stub) { 430 /* key. */ 431 if (!entry->key) 432 goto error; 433 434 new_entry->key = malloc(table->params.key_size); 435 if (!new_entry->key) 436 goto error; 437 438 memcpy(new_entry->key, entry->key, table->params.key_size); 439 440 /* key_signature. */ 441 new_entry->key_signature = entry->key_signature; 442 443 /* key_mask. */ 444 if (entry->key_mask) { 445 new_entry->key_mask = malloc(table->params.key_size); 446 if (!new_entry->key_mask) 447 goto error; 448 449 memcpy(new_entry->key_mask, 450 entry->key_mask, 451 table->params.key_size); 452 } 453 454 /* key_priority. */ 455 new_entry->key_priority = entry->key_priority; 456 } 457 458 if (data_duplicate) { 459 struct action *a; 460 uint32_t i; 461 462 /* action_id. */ 463 for (i = 0; i < table->info.n_actions; i++) 464 if (entry->action_id == table->actions[i].action_id) 465 break; 466 467 if (i >= table->info.n_actions) 468 goto error; 469 470 new_entry->action_id = entry->action_id; 471 472 /* action_data. */ 473 a = &ctl->actions[entry->action_id]; 474 if (a->data_size && !entry->action_data) 475 goto error; 476 477 /* The table layer provisions a constant action data size per 478 * entry, which should be the largest data size for all the 479 * actions enabled for the current table, and attempts to copy 480 * this many bytes each time a table entry is added, even if the 481 * specific action requires less data or even no data at all, 482 * hence we always have to allocate the max. 483 */ 484 new_entry->action_data = calloc(1, table->params.action_data_size); 485 if (!new_entry->action_data) 486 goto error; 487 488 if (a->data_size) 489 memcpy(new_entry->action_data, 490 entry->action_data, 491 a->data_size); 492 } 493 494 return new_entry; 495 496 error: 497 table_entry_free(new_entry); 498 return NULL; 499 } 500 501 static int 502 table_entry_keycmp(struct table *table, 503 struct rte_swx_table_entry *e0, 504 struct rte_swx_table_entry *e1) 505 { 506 uint32_t key_size = table->params.key_size; 507 uint32_t i; 508 509 for (i = 0; i < key_size; i++) { 510 uint8_t *key_mask0 = table->params.key_mask0; 511 uint8_t km0, km[2], k[2]; 512 513 km0 = key_mask0 ? key_mask0[i] : 0xFF; 514 515 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF; 516 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF; 517 518 k[0] = e0->key[i]; 519 k[1] = e1->key[i]; 520 521 /* Mask comparison. */ 522 if ((km[0] & km0) != (km[1] & km0)) 523 return 1; /* Not equal. */ 524 525 /* Value comparison. */ 526 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0)) 527 return 1; /* Not equal. */ 528 } 529 530 return 0; /* Equal. */ 531 } 532 533 static struct rte_swx_table_entry * 534 table_entries_find(struct table *table, struct rte_swx_table_entry *entry) 535 { 536 struct rte_swx_table_entry *e; 537 538 TAILQ_FOREACH(e, &table->entries, node) 539 if (!table_entry_keycmp(table, entry, e)) 540 return e; /* Found. */ 541 542 return NULL; /* Not found. */ 543 } 544 545 static void 546 table_entries_free(struct table *table) 547 { 548 for ( ; ; ) { 549 struct rte_swx_table_entry *entry; 550 551 entry = TAILQ_FIRST(&table->entries); 552 if (!entry) 553 break; 554 555 TAILQ_REMOVE(&table->entries, entry, node); 556 table_entry_free(entry); 557 } 558 } 559 560 static struct rte_swx_table_entry * 561 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry) 562 { 563 struct rte_swx_table_entry *e; 564 565 TAILQ_FOREACH(e, &table->pending_add, node) 566 if (!table_entry_keycmp(table, entry, e)) 567 return e; /* Found. */ 568 569 return NULL; /* Not found. */ 570 } 571 572 static void 573 table_pending_add_admit(struct table *table) 574 { 575 TAILQ_CONCAT(&table->entries, &table->pending_add, node); 576 } 577 578 static void 579 table_pending_add_free(struct table *table) 580 { 581 for ( ; ; ) { 582 struct rte_swx_table_entry *entry; 583 584 entry = TAILQ_FIRST(&table->pending_add); 585 if (!entry) 586 break; 587 588 TAILQ_REMOVE(&table->pending_add, entry, node); 589 table_entry_free(entry); 590 } 591 } 592 593 static struct rte_swx_table_entry * 594 table_pending_modify0_find(struct table *table, 595 struct rte_swx_table_entry *entry) 596 { 597 struct rte_swx_table_entry *e; 598 599 TAILQ_FOREACH(e, &table->pending_modify0, node) 600 if (!table_entry_keycmp(table, entry, e)) 601 return e; /* Found. */ 602 603 return NULL; /* Not found. */ 604 } 605 606 static void 607 table_pending_modify0_admit(struct table *table) 608 { 609 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node); 610 } 611 612 static void 613 table_pending_modify0_free(struct table *table) 614 { 615 for ( ; ; ) { 616 struct rte_swx_table_entry *entry; 617 618 entry = TAILQ_FIRST(&table->pending_modify0); 619 if (!entry) 620 break; 621 622 TAILQ_REMOVE(&table->pending_modify0, entry, node); 623 table_entry_free(entry); 624 } 625 } 626 627 static struct rte_swx_table_entry * 628 table_pending_modify1_find(struct table *table, 629 struct rte_swx_table_entry *entry) 630 { 631 struct rte_swx_table_entry *e; 632 633 TAILQ_FOREACH(e, &table->pending_modify1, node) 634 if (!table_entry_keycmp(table, entry, e)) 635 return e; /* Found. */ 636 637 return NULL; /* Not found. */ 638 } 639 640 static void 641 table_pending_modify1_admit(struct table *table) 642 { 643 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node); 644 } 645 646 static void 647 table_pending_modify1_free(struct table *table) 648 { 649 for ( ; ; ) { 650 struct rte_swx_table_entry *entry; 651 652 entry = TAILQ_FIRST(&table->pending_modify1); 653 if (!entry) 654 break; 655 656 TAILQ_REMOVE(&table->pending_modify1, entry, node); 657 table_entry_free(entry); 658 } 659 } 660 661 static struct rte_swx_table_entry * 662 table_pending_delete_find(struct table *table, 663 struct rte_swx_table_entry *entry) 664 { 665 struct rte_swx_table_entry *e; 666 667 TAILQ_FOREACH(e, &table->pending_delete, node) 668 if (!table_entry_keycmp(table, entry, e)) 669 return e; /* Found. */ 670 671 return NULL; /* Not found. */ 672 } 673 674 static void 675 table_pending_delete_admit(struct table *table) 676 { 677 TAILQ_CONCAT(&table->entries, &table->pending_delete, node); 678 } 679 680 static void 681 table_pending_delete_free(struct table *table) 682 { 683 for ( ; ; ) { 684 struct rte_swx_table_entry *entry; 685 686 entry = TAILQ_FIRST(&table->pending_delete); 687 if (!entry) 688 break; 689 690 TAILQ_REMOVE(&table->pending_delete, entry, node); 691 table_entry_free(entry); 692 } 693 } 694 695 static void 696 table_pending_default_free(struct table *table) 697 { 698 if (!table->pending_default) 699 return; 700 701 free(table->pending_default->action_data); 702 free(table->pending_default); 703 table->pending_default = NULL; 704 } 705 706 static int 707 table_is_update_pending(struct table *table, int consider_pending_default) 708 { 709 struct rte_swx_table_entry *e; 710 uint32_t n = 0; 711 712 /* Pending add. */ 713 TAILQ_FOREACH(e, &table->pending_add, node) 714 n++; 715 716 /* Pending modify. */ 717 TAILQ_FOREACH(e, &table->pending_modify1, node) 718 n++; 719 720 /* Pending delete. */ 721 TAILQ_FOREACH(e, &table->pending_delete, node) 722 n++; 723 724 /* Pending default. */ 725 if (consider_pending_default && table->pending_default) 726 n++; 727 728 return n; 729 } 730 731 static void 732 table_free(struct rte_swx_ctl_pipeline *ctl) 733 { 734 uint32_t i; 735 736 if (!ctl->tables) 737 return; 738 739 for (i = 0; i < ctl->info.n_tables; i++) { 740 struct table *table = &ctl->tables[i]; 741 742 free(table->mf); 743 free(table->actions); 744 free(table->params.key_mask0); 745 746 table_entries_free(table); 747 table_pending_add_free(table); 748 table_pending_modify0_free(table); 749 table_pending_modify1_free(table); 750 table_pending_delete_free(table); 751 table_pending_default_free(table); 752 } 753 754 free(ctl->tables); 755 ctl->tables = NULL; 756 } 757 758 static void 759 selector_group_members_free(struct selector *s, uint32_t group_id) 760 { 761 struct rte_swx_table_selector_group *group = s->groups[group_id]; 762 763 if (!group) 764 return; 765 766 for ( ; ; ) { 767 struct rte_swx_table_selector_member *m; 768 769 m = TAILQ_FIRST(&group->members); 770 if (!m) 771 break; 772 773 TAILQ_REMOVE(&group->members, m, node); 774 free(m); 775 } 776 777 free(group); 778 s->groups[group_id] = NULL; 779 } 780 781 static void 782 selector_pending_group_members_free(struct selector *s, uint32_t group_id) 783 { 784 struct rte_swx_table_selector_group *group = s->pending_groups[group_id]; 785 786 if (!group) 787 return; 788 789 for ( ; ; ) { 790 struct rte_swx_table_selector_member *m; 791 792 m = TAILQ_FIRST(&group->members); 793 if (!m) 794 break; 795 796 TAILQ_REMOVE(&group->members, m, node); 797 free(m); 798 } 799 800 free(group); 801 s->pending_groups[group_id] = NULL; 802 } 803 804 static int 805 selector_group_duplicate_to_pending(struct selector *s, uint32_t group_id) 806 { 807 struct rte_swx_table_selector_group *g, *gp; 808 struct rte_swx_table_selector_member *m; 809 810 selector_pending_group_members_free(s, group_id); 811 812 g = s->groups[group_id]; 813 gp = s->pending_groups[group_id]; 814 815 if (!gp) { 816 gp = calloc(1, sizeof(struct rte_swx_table_selector_group)); 817 if (!gp) 818 goto error; 819 820 TAILQ_INIT(&gp->members); 821 822 s->pending_groups[group_id] = gp; 823 } 824 825 if (!g) 826 return 0; 827 828 TAILQ_FOREACH(m, &g->members, node) { 829 struct rte_swx_table_selector_member *mp; 830 831 mp = calloc(1, sizeof(struct rte_swx_table_selector_member)); 832 if (!mp) 833 goto error; 834 835 memcpy(mp, m, sizeof(struct rte_swx_table_selector_member)); 836 837 TAILQ_INSERT_TAIL(&gp->members, mp, node); 838 } 839 840 return 0; 841 842 error: 843 selector_pending_group_members_free(s, group_id); 844 return -ENOMEM; 845 } 846 847 static void 848 selector_free(struct rte_swx_ctl_pipeline *ctl) 849 { 850 uint32_t i; 851 852 if (!ctl->selectors) 853 return; 854 855 for (i = 0; i < ctl->info.n_selectors; i++) { 856 struct selector *s = &ctl->selectors[i]; 857 uint32_t i; 858 859 /* selector_fields. */ 860 free(s->selector_fields); 861 862 /* groups. */ 863 if (s->groups) 864 for (i = 0; i < s->info.n_groups_max; i++) 865 selector_group_members_free(s, i); 866 867 free(s->groups); 868 869 /* pending_groups. */ 870 if (s->pending_groups) 871 for (i = 0; i < s->info.n_groups_max; i++) 872 selector_pending_group_members_free(s, i); 873 874 free(s->pending_groups); 875 876 /* groups_added. */ 877 free(s->groups_added); 878 879 /* groups_pending_delete. */ 880 free(s->groups_pending_delete); 881 882 /* params. */ 883 free(s->params.selector_mask); 884 } 885 886 free(ctl->selectors); 887 ctl->selectors = NULL; 888 } 889 890 static struct selector * 891 selector_find(struct rte_swx_ctl_pipeline *ctl, const char *selector_name) 892 { 893 uint32_t i; 894 895 for (i = 0; i < ctl->info.n_selectors; i++) { 896 struct selector *s = &ctl->selectors[i]; 897 898 if (!strcmp(selector_name, s->info.name)) 899 return s; 900 } 901 902 return NULL; 903 } 904 905 static int 906 selector_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id) 907 { 908 struct selector *s = &ctl->selectors[selector_id]; 909 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL; 910 uint8_t *selector_mask = NULL; 911 uint32_t selector_size = 0, selector_offset = 0, i; 912 913 /* Find first (smallest offset) and last (biggest offset) match fields. */ 914 first = &s->selector_fields[0]; 915 last = &s->selector_fields[0]; 916 917 for (i = 1; i < s->info.n_selector_fields; i++) { 918 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i]; 919 920 if (f->offset < first->offset) 921 first = f; 922 923 if (f->offset > last->offset) 924 last = f; 925 } 926 927 /* selector_offset. */ 928 selector_offset = first->offset / 8; 929 930 /* selector_size. */ 931 selector_size = (last->offset + last->n_bits - first->offset) / 8; 932 933 /* selector_mask. */ 934 selector_mask = calloc(1, selector_size); 935 if (!selector_mask) 936 return -ENOMEM; 937 938 for (i = 0; i < s->info.n_selector_fields; i++) { 939 struct rte_swx_ctl_table_match_field_info *f = &s->selector_fields[i]; 940 uint32_t start; 941 size_t size; 942 943 start = (f->offset - first->offset) / 8; 944 size = f->n_bits / 8; 945 946 memset(&selector_mask[start], 0xFF, size); 947 } 948 949 /* Fill in. */ 950 s->params.group_id_offset = s->group_id_field.offset / 8; 951 s->params.selector_size = selector_size; 952 s->params.selector_offset = selector_offset; 953 s->params.selector_mask = selector_mask; 954 s->params.member_id_offset = s->member_id_field.offset / 8; 955 s->params.n_groups_max = s->info.n_groups_max; 956 s->params.n_members_per_group_max = s->info.n_members_per_group_max; 957 958 return 0; 959 } 960 961 static void 962 learner_pending_default_free(struct learner *l) 963 { 964 if (!l->pending_default) 965 return; 966 967 free(l->pending_default->action_data); 968 free(l->pending_default); 969 l->pending_default = NULL; 970 } 971 972 973 static void 974 learner_free(struct rte_swx_ctl_pipeline *ctl) 975 { 976 uint32_t i; 977 978 if (!ctl->learners) 979 return; 980 981 for (i = 0; i < ctl->info.n_learners; i++) { 982 struct learner *l = &ctl->learners[i]; 983 984 free(l->mf); 985 free(l->actions); 986 987 learner_pending_default_free(l); 988 } 989 990 free(ctl->learners); 991 ctl->learners = NULL; 992 } 993 994 static struct learner * 995 learner_find(struct rte_swx_ctl_pipeline *ctl, const char *learner_name) 996 { 997 uint32_t i; 998 999 for (i = 0; i < ctl->info.n_learners; i++) { 1000 struct learner *l = &ctl->learners[i]; 1001 1002 if (!strcmp(learner_name, l->info.name)) 1003 return l; 1004 } 1005 1006 return NULL; 1007 } 1008 1009 static uint32_t 1010 learner_action_data_size_get(struct rte_swx_ctl_pipeline *ctl, struct learner *l) 1011 { 1012 uint32_t action_data_size = 0, i; 1013 1014 for (i = 0; i < l->info.n_actions; i++) { 1015 uint32_t action_id = l->actions[i].action_id; 1016 struct action *a = &ctl->actions[action_id]; 1017 1018 if (a->data_size > action_data_size) 1019 action_data_size = a->data_size; 1020 } 1021 1022 return action_data_size; 1023 } 1024 1025 static void 1026 table_state_free(struct rte_swx_ctl_pipeline *ctl) 1027 { 1028 uint32_t table_base_index, selector_base_index, learner_base_index, i; 1029 1030 if (!ctl->ts_next) 1031 return; 1032 1033 /* For each table, free its table state. */ 1034 table_base_index = 0; 1035 for (i = 0; i < ctl->info.n_tables; i++) { 1036 struct table *table = &ctl->tables[i]; 1037 struct rte_swx_table_state *ts = &ctl->ts_next[table_base_index + i]; 1038 1039 /* Default action data. */ 1040 free(ts->default_action_data); 1041 1042 /* Table object. */ 1043 if (!table->is_stub && table->ops.free && ts->obj) 1044 table->ops.free(ts->obj); 1045 } 1046 1047 /* For each selector table, free its table state. */ 1048 selector_base_index = ctl->info.n_tables; 1049 for (i = 0; i < ctl->info.n_selectors; i++) { 1050 struct rte_swx_table_state *ts = &ctl->ts_next[selector_base_index + i]; 1051 1052 /* Table object. */ 1053 rte_swx_table_selector_free(ts->obj); 1054 } 1055 1056 /* For each learner table, free its table state. */ 1057 learner_base_index = ctl->info.n_tables + ctl->info.n_selectors; 1058 for (i = 0; i < ctl->info.n_learners; i++) { 1059 struct rte_swx_table_state *ts = &ctl->ts_next[learner_base_index + i]; 1060 1061 /* Default action data. */ 1062 free(ts->default_action_data); 1063 } 1064 1065 free(ctl->ts_next); 1066 ctl->ts_next = NULL; 1067 } 1068 1069 static int 1070 table_state_create(struct rte_swx_ctl_pipeline *ctl) 1071 { 1072 uint32_t table_base_index, selector_base_index, learner_base_index, i; 1073 int status = 0; 1074 1075 ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors + ctl->info.n_learners, 1076 sizeof(struct rte_swx_table_state)); 1077 if (!ctl->ts_next) { 1078 status = -ENOMEM; 1079 goto error; 1080 } 1081 1082 /* Tables. */ 1083 table_base_index = 0; 1084 for (i = 0; i < ctl->info.n_tables; i++) { 1085 struct table *table = &ctl->tables[i]; 1086 struct rte_swx_table_state *ts = &ctl->ts[table_base_index + i]; 1087 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_base_index + i]; 1088 1089 /* Table object. */ 1090 if (!table->is_stub && table->ops.add) { 1091 ts_next->obj = table->ops.create(&table->params, 1092 &table->entries, 1093 table->info.args, 1094 ctl->numa_node); 1095 if (!ts_next->obj) { 1096 status = -ENODEV; 1097 goto error; 1098 } 1099 } 1100 1101 if (!table->is_stub && !table->ops.add) 1102 ts_next->obj = ts->obj; 1103 1104 /* Default action data: duplicate from current table state. */ 1105 ts_next->default_action_data = 1106 malloc(table->params.action_data_size); 1107 if (!ts_next->default_action_data) { 1108 status = -ENOMEM; 1109 goto error; 1110 } 1111 1112 memcpy(ts_next->default_action_data, 1113 ts->default_action_data, 1114 table->params.action_data_size); 1115 1116 ts_next->default_action_id = ts->default_action_id; 1117 } 1118 1119 /* Selector tables. */ 1120 selector_base_index = ctl->info.n_tables; 1121 for (i = 0; i < ctl->info.n_selectors; i++) { 1122 struct selector *s = &ctl->selectors[i]; 1123 struct rte_swx_table_state *ts_next = &ctl->ts_next[selector_base_index + i]; 1124 1125 /* Table object. */ 1126 ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node); 1127 if (!ts_next->obj) { 1128 status = -ENODEV; 1129 goto error; 1130 } 1131 } 1132 1133 /* Learner tables. */ 1134 learner_base_index = ctl->info.n_tables + ctl->info.n_selectors; 1135 for (i = 0; i < ctl->info.n_learners; i++) { 1136 struct learner *l = &ctl->learners[i]; 1137 struct rte_swx_table_state *ts = &ctl->ts[learner_base_index + i]; 1138 struct rte_swx_table_state *ts_next = &ctl->ts_next[learner_base_index + i]; 1139 1140 /* Table object: duplicate from the current table state. */ 1141 ts_next->obj = ts->obj; 1142 1143 /* Default action data: duplicate from the current table state. */ 1144 ts_next->default_action_data = malloc(l->action_data_size); 1145 if (!ts_next->default_action_data) { 1146 status = -ENOMEM; 1147 goto error; 1148 } 1149 1150 memcpy(ts_next->default_action_data, 1151 ts->default_action_data, 1152 l->action_data_size); 1153 1154 ts_next->default_action_id = ts->default_action_id; 1155 } 1156 1157 return 0; 1158 1159 error: 1160 table_state_free(ctl); 1161 return status; 1162 } 1163 1164 /* Global list of pipeline instances. */ 1165 TAILQ_HEAD(rte_swx_ctl_pipeline_list, rte_tailq_entry); 1166 1167 static struct rte_tailq_elem rte_swx_ctl_pipeline_tailq = { 1168 .name = "RTE_SWX_CTL_PIPELINE", 1169 }; 1170 1171 EAL_REGISTER_TAILQ(rte_swx_ctl_pipeline_tailq) 1172 1173 struct rte_swx_ctl_pipeline * 1174 rte_swx_ctl_pipeline_find(const char *name) 1175 { 1176 struct rte_swx_ctl_pipeline_list *ctl_list; 1177 struct rte_tailq_entry *te = NULL; 1178 1179 if (!name || !name[0] || (strnlen(name, RTE_SWX_CTL_NAME_SIZE) >= RTE_SWX_CTL_NAME_SIZE)) 1180 return NULL; 1181 1182 ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list); 1183 1184 rte_mcfg_tailq_read_lock(); 1185 1186 TAILQ_FOREACH(te, ctl_list, next) { 1187 struct rte_swx_ctl_pipeline *ctl = (struct rte_swx_ctl_pipeline *)te->data; 1188 1189 if (!strncmp(name, ctl->info.name, sizeof(ctl->info.name))) { 1190 rte_mcfg_tailq_read_unlock(); 1191 return ctl; 1192 } 1193 } 1194 1195 rte_mcfg_tailq_read_unlock(); 1196 return NULL; 1197 } 1198 1199 static int 1200 ctl_register(struct rte_swx_ctl_pipeline *ctl) 1201 { 1202 struct rte_swx_ctl_pipeline_list *ctl_list; 1203 struct rte_tailq_entry *te = NULL; 1204 1205 ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list); 1206 1207 rte_mcfg_tailq_write_lock(); 1208 1209 TAILQ_FOREACH(te, ctl_list, next) { 1210 struct rte_swx_ctl_pipeline *ctl_crt = (struct rte_swx_ctl_pipeline *)te->data; 1211 1212 if (!strncmp(ctl->info.name, ctl_crt->info.name, sizeof(ctl->info.name))) { 1213 rte_mcfg_tailq_write_unlock(); 1214 return -EEXIST; 1215 } 1216 } 1217 1218 te = calloc(1, sizeof(struct rte_tailq_entry)); 1219 if (!te) { 1220 rte_mcfg_tailq_write_unlock(); 1221 return -ENOMEM; 1222 } 1223 1224 te->data = (void *)ctl; 1225 TAILQ_INSERT_TAIL(ctl_list, te, next); 1226 rte_mcfg_tailq_write_unlock(); 1227 return 0; 1228 } 1229 1230 static void 1231 ctl_unregister(struct rte_swx_ctl_pipeline *ctl) 1232 { 1233 struct rte_swx_ctl_pipeline_list *ctl_list; 1234 struct rte_tailq_entry *te = NULL; 1235 1236 ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list); 1237 1238 rte_mcfg_tailq_write_lock(); 1239 1240 TAILQ_FOREACH(te, ctl_list, next) { 1241 if (te->data == (void *)ctl) { 1242 TAILQ_REMOVE(ctl_list, te, next); 1243 rte_mcfg_tailq_write_unlock(); 1244 free(te); 1245 return; 1246 } 1247 } 1248 1249 rte_mcfg_tailq_write_unlock(); 1250 } 1251 1252 void 1253 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl) 1254 { 1255 if (!ctl) 1256 return; 1257 1258 if (ctl->info.name[0]) 1259 ctl_unregister(ctl); 1260 1261 action_free(ctl); 1262 1263 table_state_free(ctl); 1264 1265 learner_free(ctl); 1266 1267 selector_free(ctl); 1268 1269 table_free(ctl); 1270 1271 free(ctl); 1272 } 1273 1274 struct rte_swx_ctl_pipeline * 1275 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p) 1276 { 1277 struct rte_swx_ctl_pipeline *ctl = NULL; 1278 uint32_t i; 1279 int status; 1280 1281 if (!p) 1282 goto error; 1283 1284 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline)); 1285 if (!ctl) 1286 goto error; 1287 1288 /* info. */ 1289 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info); 1290 if (status) 1291 goto error; 1292 1293 /* numa_node. */ 1294 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node); 1295 if (status) 1296 goto error; 1297 1298 /* p. */ 1299 ctl->p = p; 1300 1301 /* actions. */ 1302 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action)); 1303 if (!ctl->actions) 1304 goto error; 1305 1306 for (i = 0; i < ctl->info.n_actions; i++) { 1307 struct action *a = &ctl->actions[i]; 1308 uint32_t j; 1309 1310 /* info. */ 1311 status = rte_swx_ctl_action_info_get(p, i, &a->info); 1312 if (status) 1313 goto error; 1314 1315 /* args. */ 1316 a->args = calloc(a->info.n_args, 1317 sizeof(struct rte_swx_ctl_action_arg_info)); 1318 if (!a->args) 1319 goto error; 1320 1321 for (j = 0; j < a->info.n_args; j++) { 1322 status = rte_swx_ctl_action_arg_info_get(p, 1323 i, 1324 j, 1325 &a->args[j]); 1326 if (status) 1327 goto error; 1328 } 1329 1330 /* data_size. */ 1331 for (j = 0; j < a->info.n_args; j++) { 1332 struct rte_swx_ctl_action_arg_info *info = &a->args[j]; 1333 1334 a->data_size += info->n_bits; 1335 } 1336 1337 a->data_size = (a->data_size + 7) / 8; 1338 } 1339 1340 /* tables. */ 1341 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table)); 1342 if (!ctl->tables) 1343 goto error; 1344 1345 for (i = 0; i < ctl->info.n_tables; i++) { 1346 struct table *t = &ctl->tables[i]; 1347 1348 TAILQ_INIT(&t->entries); 1349 TAILQ_INIT(&t->pending_add); 1350 TAILQ_INIT(&t->pending_modify0); 1351 TAILQ_INIT(&t->pending_modify1); 1352 TAILQ_INIT(&t->pending_delete); 1353 } 1354 1355 for (i = 0; i < ctl->info.n_tables; i++) { 1356 struct table *t = &ctl->tables[i]; 1357 uint32_t j; 1358 1359 /* info. */ 1360 status = rte_swx_ctl_table_info_get(p, i, &t->info); 1361 if (status) 1362 goto error; 1363 1364 /* mf. */ 1365 t->mf = calloc(t->info.n_match_fields, 1366 sizeof(struct rte_swx_ctl_table_match_field_info)); 1367 if (!t->mf) 1368 goto error; 1369 1370 for (j = 0; j < t->info.n_match_fields; j++) { 1371 status = rte_swx_ctl_table_match_field_info_get(p, 1372 i, 1373 j, 1374 &t->mf[j]); 1375 if (status) 1376 goto error; 1377 } 1378 1379 /* actions. */ 1380 t->actions = calloc(t->info.n_actions, 1381 sizeof(struct rte_swx_ctl_table_action_info)); 1382 if (!t->actions) 1383 goto error; 1384 1385 for (j = 0; j < t->info.n_actions; j++) { 1386 status = rte_swx_ctl_table_action_info_get(p, 1387 i, 1388 j, 1389 &t->actions[j]); 1390 if (status || 1391 t->actions[j].action_id >= ctl->info.n_actions) 1392 goto error; 1393 } 1394 1395 /* ops, is_stub. */ 1396 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub); 1397 if (status) 1398 goto error; 1399 1400 if ((t->is_stub && t->info.n_match_fields) || 1401 (!t->is_stub && !t->info.n_match_fields)) 1402 goto error; 1403 1404 /* params. */ 1405 status = table_params_get(ctl, i); 1406 if (status) 1407 goto error; 1408 } 1409 1410 /* selector tables. */ 1411 ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector)); 1412 if (!ctl->selectors) 1413 goto error; 1414 1415 for (i = 0; i < ctl->info.n_selectors; i++) { 1416 struct selector *s = &ctl->selectors[i]; 1417 uint32_t j; 1418 1419 /* info. */ 1420 status = rte_swx_ctl_selector_info_get(p, i, &s->info); 1421 if (status) 1422 goto error; 1423 1424 /* group_id field. */ 1425 status = rte_swx_ctl_selector_group_id_field_info_get(p, 1426 i, 1427 &s->group_id_field); 1428 if (status) 1429 goto error; 1430 1431 /* selector fields. */ 1432 s->selector_fields = calloc(s->info.n_selector_fields, 1433 sizeof(struct rte_swx_ctl_table_match_field_info)); 1434 if (!s->selector_fields) 1435 goto error; 1436 1437 for (j = 0; j < s->info.n_selector_fields; j++) { 1438 status = rte_swx_ctl_selector_field_info_get(p, 1439 i, 1440 j, 1441 &s->selector_fields[j]); 1442 if (status) 1443 goto error; 1444 } 1445 1446 /* member_id field. */ 1447 status = rte_swx_ctl_selector_member_id_field_info_get(p, 1448 i, 1449 &s->member_id_field); 1450 if (status) 1451 goto error; 1452 1453 /* groups. */ 1454 s->groups = calloc(s->info.n_groups_max, 1455 sizeof(struct rte_swx_table_selector_group *)); 1456 if (!s->groups) 1457 goto error; 1458 1459 /* pending_groups. */ 1460 s->pending_groups = calloc(s->info.n_groups_max, 1461 sizeof(struct rte_swx_table_selector_group *)); 1462 if (!s->pending_groups) 1463 goto error; 1464 1465 /* groups_added. */ 1466 s->groups_added = calloc(s->info.n_groups_max, sizeof(int)); 1467 if (!s->groups_added) 1468 goto error; 1469 1470 /* groups_pending_delete. */ 1471 s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int)); 1472 if (!s->groups_pending_delete) 1473 goto error; 1474 1475 /* params. */ 1476 status = selector_params_get(ctl, i); 1477 if (status) 1478 goto error; 1479 } 1480 1481 /* learner tables. */ 1482 ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner)); 1483 if (!ctl->learners) 1484 goto error; 1485 1486 for (i = 0; i < ctl->info.n_learners; i++) { 1487 struct learner *l = &ctl->learners[i]; 1488 uint32_t j; 1489 1490 /* info. */ 1491 status = rte_swx_ctl_learner_info_get(p, i, &l->info); 1492 if (status) 1493 goto error; 1494 1495 /* mf. */ 1496 l->mf = calloc(l->info.n_match_fields, 1497 sizeof(struct rte_swx_ctl_table_match_field_info)); 1498 if (!l->mf) 1499 goto error; 1500 1501 for (j = 0; j < l->info.n_match_fields; j++) { 1502 status = rte_swx_ctl_learner_match_field_info_get(p, 1503 i, 1504 j, 1505 &l->mf[j]); 1506 if (status) 1507 goto error; 1508 } 1509 1510 /* actions. */ 1511 l->actions = calloc(l->info.n_actions, 1512 sizeof(struct rte_swx_ctl_table_action_info)); 1513 if (!l->actions) 1514 goto error; 1515 1516 for (j = 0; j < l->info.n_actions; j++) { 1517 status = rte_swx_ctl_learner_action_info_get(p, 1518 i, 1519 j, 1520 &l->actions[j]); 1521 if (status || l->actions[j].action_id >= ctl->info.n_actions) 1522 goto error; 1523 } 1524 1525 /* action_data_size. */ 1526 l->action_data_size = learner_action_data_size_get(ctl, l); 1527 } 1528 1529 /* ts. */ 1530 status = rte_swx_pipeline_table_state_get(p, &ctl->ts); 1531 if (status) 1532 goto error; 1533 1534 /* ts_next. */ 1535 status = table_state_create(ctl); 1536 if (status) 1537 goto error; 1538 1539 if (ctl->info.name[0]) { 1540 status = ctl_register(ctl); 1541 if (status) 1542 goto error; 1543 } 1544 1545 return ctl; 1546 1547 error: 1548 rte_swx_ctl_pipeline_free(ctl); 1549 return NULL; 1550 } 1551 1552 int 1553 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl, 1554 const char *table_name, 1555 struct rte_swx_table_entry *entry) 1556 { 1557 struct table *table; 1558 struct rte_swx_table_entry *new_entry, *existing_entry; 1559 uint32_t table_id; 1560 1561 CHECK(ctl, EINVAL); 1562 CHECK(table_name && table_name[0], EINVAL); 1563 1564 table = table_find(ctl, table_name); 1565 CHECK(table, EINVAL); 1566 table_id = table - ctl->tables; 1567 1568 CHECK(entry, EINVAL); 1569 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL); 1570 1571 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1); 1572 CHECK(new_entry, ENOMEM); 1573 1574 /* The new entry is found in the table->entries list: 1575 * - Add the new entry to the table->pending_modify1 list; 1576 * - Move the existing entry from the table->entries list to the 1577 * table->pending_modify0 list. 1578 */ 1579 existing_entry = table_entries_find(table, entry); 1580 if (existing_entry) { 1581 TAILQ_INSERT_TAIL(&table->pending_modify1, 1582 new_entry, 1583 node); 1584 1585 TAILQ_REMOVE(&table->entries, 1586 existing_entry, 1587 node); 1588 1589 TAILQ_INSERT_TAIL(&table->pending_modify0, 1590 existing_entry, 1591 node); 1592 1593 return 0; 1594 } 1595 1596 /* The new entry is found in the table->pending_add list: 1597 * - Replace the entry in the table->pending_add list with the new entry 1598 * (and free the replaced entry). 1599 */ 1600 existing_entry = table_pending_add_find(table, entry); 1601 if (existing_entry) { 1602 TAILQ_INSERT_AFTER(&table->pending_add, 1603 existing_entry, 1604 new_entry, 1605 node); 1606 1607 TAILQ_REMOVE(&table->pending_add, 1608 existing_entry, 1609 node); 1610 1611 table_entry_free(existing_entry); 1612 1613 return 0; 1614 } 1615 1616 /* The new entry is found in the table->pending_modify1 list: 1617 * - Replace the entry in the table->pending_modify1 list with the new 1618 * entry (and free the replaced entry). 1619 */ 1620 existing_entry = table_pending_modify1_find(table, entry); 1621 if (existing_entry) { 1622 TAILQ_INSERT_AFTER(&table->pending_modify1, 1623 existing_entry, 1624 new_entry, 1625 node); 1626 1627 TAILQ_REMOVE(&table->pending_modify1, 1628 existing_entry, 1629 node); 1630 1631 table_entry_free(existing_entry); 1632 1633 return 0; 1634 } 1635 1636 /* The new entry is found in the table->pending_delete list: 1637 * - Add the new entry to the table->pending_modify1 list; 1638 * - Move the existing entry from the table->pending_delete list to the 1639 * table->pending_modify0 list. 1640 */ 1641 existing_entry = table_pending_delete_find(table, entry); 1642 if (existing_entry) { 1643 TAILQ_INSERT_TAIL(&table->pending_modify1, 1644 new_entry, 1645 node); 1646 1647 TAILQ_REMOVE(&table->pending_delete, 1648 existing_entry, 1649 node); 1650 1651 TAILQ_INSERT_TAIL(&table->pending_modify0, 1652 existing_entry, 1653 node); 1654 1655 return 0; 1656 } 1657 1658 /* The new entry is not found in any of the above lists: 1659 * - Add the new entry to the table->pending_add list. 1660 */ 1661 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node); 1662 1663 return 0; 1664 } 1665 1666 int 1667 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl, 1668 const char *table_name, 1669 struct rte_swx_table_entry *entry) 1670 { 1671 struct table *table; 1672 struct rte_swx_table_entry *existing_entry; 1673 uint32_t table_id; 1674 1675 CHECK(ctl, EINVAL); 1676 1677 CHECK(table_name && table_name[0], EINVAL); 1678 table = table_find(ctl, table_name); 1679 CHECK(table, EINVAL); 1680 table_id = table - ctl->tables; 1681 1682 CHECK(entry, EINVAL); 1683 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL); 1684 1685 /* The entry is found in the table->entries list: 1686 * - Move the existing entry from the table->entries list to the 1687 * table->pending_delete list. 1688 */ 1689 existing_entry = table_entries_find(table, entry); 1690 if (existing_entry) { 1691 TAILQ_REMOVE(&table->entries, 1692 existing_entry, 1693 node); 1694 1695 TAILQ_INSERT_TAIL(&table->pending_delete, 1696 existing_entry, 1697 node); 1698 1699 return 0; 1700 } 1701 1702 /* The entry is found in the table->pending_add list: 1703 * - Remove the entry from the table->pending_add list and free it. 1704 */ 1705 existing_entry = table_pending_add_find(table, entry); 1706 if (existing_entry) { 1707 TAILQ_REMOVE(&table->pending_add, 1708 existing_entry, 1709 node); 1710 1711 table_entry_free(existing_entry); 1712 } 1713 1714 /* The entry is found in the table->pending_modify1 list: 1715 * - Free the entry in the table->pending_modify1 list; 1716 * - Move the existing entry from the table->pending_modify0 list to the 1717 * table->pending_delete list. 1718 */ 1719 existing_entry = table_pending_modify1_find(table, entry); 1720 if (existing_entry) { 1721 struct rte_swx_table_entry *real_existing_entry; 1722 1723 TAILQ_REMOVE(&table->pending_modify1, 1724 existing_entry, 1725 node); 1726 1727 table_entry_free(existing_entry); 1728 1729 real_existing_entry = table_pending_modify0_find(table, entry); 1730 CHECK(real_existing_entry, EINVAL); /* Coverity. */ 1731 1732 TAILQ_REMOVE(&table->pending_modify0, 1733 real_existing_entry, 1734 node); 1735 1736 TAILQ_INSERT_TAIL(&table->pending_delete, 1737 real_existing_entry, 1738 node); 1739 1740 return 0; 1741 } 1742 1743 /* The entry is found in the table->pending_delete list: 1744 * - Do nothing: the existing entry is already in the 1745 * table->pending_delete list, i.e. already marked for delete, so 1746 * simply keep it there as it is. 1747 */ 1748 1749 /* The entry is not found in any of the above lists: 1750 * - Do nothing: no existing entry to delete. 1751 */ 1752 1753 return 0; 1754 } 1755 1756 int 1757 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl, 1758 const char *table_name, 1759 struct rte_swx_table_entry *entry) 1760 { 1761 struct table *table; 1762 struct rte_swx_table_entry *new_entry; 1763 uint32_t table_id; 1764 1765 CHECK(ctl, EINVAL); 1766 1767 CHECK(table_name && table_name[0], EINVAL); 1768 table = table_find(ctl, table_name); 1769 CHECK(table, EINVAL); 1770 table_id = table - ctl->tables; 1771 CHECK(!table->info.default_action_is_const, EINVAL); 1772 1773 CHECK(entry, EINVAL); 1774 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL); 1775 1776 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1); 1777 CHECK(new_entry, ENOMEM); 1778 1779 table_pending_default_free(table); 1780 1781 table->pending_default = new_entry; 1782 return 0; 1783 } 1784 1785 1786 static void 1787 table_entry_list_free(struct rte_swx_table_entry_list *list) 1788 { 1789 for ( ; ; ) { 1790 struct rte_swx_table_entry *entry; 1791 1792 entry = TAILQ_FIRST(list); 1793 if (!entry) 1794 break; 1795 1796 TAILQ_REMOVE(list, entry, node); 1797 table_entry_free(entry); 1798 } 1799 } 1800 1801 static int 1802 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl, 1803 uint32_t table_id, 1804 struct rte_swx_table_entry_list *dst, 1805 struct rte_swx_table_entry_list *src) 1806 { 1807 struct rte_swx_table_entry *src_entry; 1808 1809 TAILQ_FOREACH(src_entry, src, node) { 1810 struct rte_swx_table_entry *dst_entry; 1811 1812 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1); 1813 if (!dst_entry) 1814 goto error; 1815 1816 TAILQ_INSERT_TAIL(dst, dst_entry, node); 1817 } 1818 1819 return 0; 1820 1821 error: 1822 table_entry_list_free(dst); 1823 return -ENOMEM; 1824 } 1825 1826 /* This commit stage contains all the operations that can fail; in case ANY of 1827 * them fails for ANY table, ALL of them are rolled back for ALL the tables. 1828 */ 1829 static int 1830 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl, 1831 uint32_t table_id, 1832 uint32_t after_swap) 1833 { 1834 struct table *table = &ctl->tables[table_id]; 1835 struct rte_swx_table_state *ts = &ctl->ts[table_id]; 1836 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id]; 1837 1838 if (table->is_stub || !table_is_update_pending(table, 0)) 1839 return 0; 1840 1841 /* 1842 * Current table supports incremental update. 1843 */ 1844 if (table->ops.add) { 1845 /* Reset counters. */ 1846 table->n_add = 0; 1847 table->n_modify = 0; 1848 table->n_delete = 0; 1849 1850 /* Add pending rules. */ 1851 struct rte_swx_table_entry *entry; 1852 1853 TAILQ_FOREACH(entry, &table->pending_add, node) { 1854 int status; 1855 1856 status = table->ops.add(ts_next->obj, entry); 1857 if (status) 1858 return status; 1859 1860 table->n_add++; 1861 } 1862 1863 /* Modify pending rules. */ 1864 TAILQ_FOREACH(entry, &table->pending_modify1, node) { 1865 int status; 1866 1867 status = table->ops.add(ts_next->obj, entry); 1868 if (status) 1869 return status; 1870 1871 table->n_modify++; 1872 } 1873 1874 /* Delete pending rules. */ 1875 TAILQ_FOREACH(entry, &table->pending_delete, node) { 1876 int status; 1877 1878 status = table->ops.del(ts_next->obj, entry); 1879 if (status) 1880 return status; 1881 1882 table->n_delete++; 1883 } 1884 1885 return 0; 1886 } 1887 1888 /* 1889 * Current table does NOT support incremental update. 1890 */ 1891 if (!after_swap) { 1892 struct rte_swx_table_entry_list list; 1893 int status; 1894 1895 /* Create updated list of entries included. */ 1896 TAILQ_INIT(&list); 1897 1898 status = table_entry_list_duplicate(ctl, 1899 table_id, 1900 &list, 1901 &table->entries); 1902 if (status) 1903 goto error; 1904 1905 status = table_entry_list_duplicate(ctl, 1906 table_id, 1907 &list, 1908 &table->pending_add); 1909 if (status) 1910 goto error; 1911 1912 status = table_entry_list_duplicate(ctl, 1913 table_id, 1914 &list, 1915 &table->pending_modify1); 1916 if (status) 1917 goto error; 1918 1919 /* Create new table object with the updates included. */ 1920 ts_next->obj = table->ops.create(&table->params, 1921 &list, 1922 table->info.args, 1923 ctl->numa_node); 1924 if (!ts_next->obj) { 1925 status = -ENODEV; 1926 goto error; 1927 } 1928 1929 table_entry_list_free(&list); 1930 1931 return 0; 1932 1933 error: 1934 table_entry_list_free(&list); 1935 return status; 1936 } 1937 1938 /* Free the old table object. */ 1939 if (ts_next->obj && table->ops.free) 1940 table->ops.free(ts_next->obj); 1941 1942 /* Copy over the new table object. */ 1943 ts_next->obj = ts->obj; 1944 1945 return 0; 1946 } 1947 1948 /* This commit stage contains all the operations that cannot fail. They are 1949 * executed only if the previous stage was successful for ALL the tables. Hence, 1950 * none of these operations has to be rolled back for ANY table. 1951 */ 1952 static void 1953 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 1954 { 1955 struct table *table = &ctl->tables[table_id]; 1956 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id]; 1957 struct action *a; 1958 uint8_t *action_data; 1959 uint64_t action_id; 1960 1961 /* Copy the pending default entry. */ 1962 if (!table->pending_default) 1963 return; 1964 1965 action_id = table->pending_default->action_id; 1966 action_data = table->pending_default->action_data; 1967 a = &ctl->actions[action_id]; 1968 1969 if (a->data_size) 1970 memcpy(ts_next->default_action_data, action_data, a->data_size); 1971 1972 ts_next->default_action_id = action_id; 1973 } 1974 1975 /* This last commit stage is simply finalizing a successful commit operation. 1976 * This stage is only executed if all the previous stages were successful. This 1977 * stage cannot fail. 1978 */ 1979 static void 1980 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 1981 { 1982 struct table *table = &ctl->tables[table_id]; 1983 1984 /* Move all the pending add entries to the table, as they are now part 1985 * of the table. 1986 */ 1987 table_pending_add_admit(table); 1988 1989 /* Move all the pending modify1 entries to table, are they are now part 1990 * of the table. Free up all the pending modify0 entries, as they are no 1991 * longer part of the table. 1992 */ 1993 table_pending_modify1_admit(table); 1994 table_pending_modify0_free(table); 1995 1996 /* Free up all the pending delete entries, as they are no longer part of 1997 * the table. 1998 */ 1999 table_pending_delete_free(table); 2000 2001 /* Free up the pending default entry, as it is now part of the table. */ 2002 table_pending_default_free(table); 2003 } 2004 2005 /* The rollback stage is only executed when the commit failed, i.e. ANY of the 2006 * commit operations that can fail did fail for ANY table. It reverts ALL the 2007 * tables to their state before the commit started, as if the commit never 2008 * happened. 2009 */ 2010 static void 2011 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 2012 { 2013 struct table *table = &ctl->tables[table_id]; 2014 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id]; 2015 2016 if (table->is_stub || !table_is_update_pending(table, 0)) 2017 return; 2018 2019 if (table->ops.add) { 2020 struct rte_swx_table_entry *entry; 2021 2022 /* Add back all the entries that were just deleted. */ 2023 TAILQ_FOREACH(entry, &table->pending_delete, node) { 2024 if (!table->n_delete) 2025 break; 2026 2027 table->ops.add(ts_next->obj, entry); 2028 table->n_delete--; 2029 } 2030 2031 /* Add back the old copy for all the entries that were just 2032 * modified. 2033 */ 2034 TAILQ_FOREACH(entry, &table->pending_modify0, node) { 2035 if (!table->n_modify) 2036 break; 2037 2038 table->ops.add(ts_next->obj, entry); 2039 table->n_modify--; 2040 } 2041 2042 /* Delete all the entries that were just added. */ 2043 TAILQ_FOREACH(entry, &table->pending_add, node) { 2044 if (!table->n_add) 2045 break; 2046 2047 table->ops.del(ts_next->obj, entry); 2048 table->n_add--; 2049 } 2050 } else { 2051 struct rte_swx_table_state *ts = &ctl->ts[table_id]; 2052 2053 /* Free the new table object, as update was cancelled. */ 2054 if (ts_next->obj && table->ops.free) 2055 table->ops.free(ts_next->obj); 2056 2057 /* Reinstate the old table object. */ 2058 ts_next->obj = ts->obj; 2059 } 2060 } 2061 2062 /* This stage is conditionally executed (as instructed by the user) after a 2063 * failed commit operation to remove ALL the pending work for ALL the tables. 2064 */ 2065 static void 2066 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 2067 { 2068 struct table *table = &ctl->tables[table_id]; 2069 2070 /* Free up all the pending add entries, as none of them is part of the 2071 * table. 2072 */ 2073 table_pending_add_free(table); 2074 2075 /* Free up all the pending modify1 entries, as none of them made it to 2076 * the table. Add back all the pending modify0 entries, as none of them 2077 * was deleted from the table. 2078 */ 2079 table_pending_modify1_free(table); 2080 table_pending_modify0_admit(table); 2081 2082 /* Add back all the pending delete entries, as none of them was deleted 2083 * from the table. 2084 */ 2085 table_pending_delete_admit(table); 2086 2087 /* Free up the pending default entry, as it is no longer going to be 2088 * added to the table. 2089 */ 2090 table_pending_default_free(table); 2091 } 2092 2093 int 2094 rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl, 2095 const char *selector_name, 2096 uint32_t *group_id) 2097 { 2098 struct selector *s; 2099 uint32_t i; 2100 2101 /* Check input arguments. */ 2102 if (!ctl || !selector_name || !selector_name[0] || !group_id) 2103 return -EINVAL; 2104 2105 s = selector_find(ctl, selector_name); 2106 if (!s) 2107 return -EINVAL; 2108 2109 /* Find an unused group. */ 2110 for (i = 0; i < s->info.n_groups_max; i++) 2111 if (!s->groups_added[i]) { 2112 *group_id = i; 2113 s->groups_added[i] = 1; 2114 return 0; 2115 } 2116 2117 return -ENOSPC; 2118 } 2119 2120 int 2121 rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl, 2122 const char *selector_name, 2123 uint32_t group_id) 2124 { 2125 struct selector *s; 2126 struct rte_swx_table_selector_group *group; 2127 2128 /* Check input arguments. */ 2129 if (!ctl || !selector_name || !selector_name[0]) 2130 return -EINVAL; 2131 2132 s = selector_find(ctl, selector_name); 2133 if (!s || 2134 (group_id >= s->info.n_groups_max) || 2135 !s->groups_added[group_id]) 2136 return -EINVAL; 2137 2138 /* Check if this group is already scheduled for deletion. */ 2139 if (s->groups_pending_delete[group_id]) 2140 return 0; 2141 2142 /* Initialize the pending group, if needed. */ 2143 if (!s->pending_groups[group_id]) { 2144 int status; 2145 2146 status = selector_group_duplicate_to_pending(s, group_id); 2147 if (status) 2148 return status; 2149 } 2150 2151 group = s->pending_groups[group_id]; 2152 2153 /* Schedule removal of all the members from the current group. */ 2154 for ( ; ; ) { 2155 struct rte_swx_table_selector_member *m; 2156 2157 m = TAILQ_FIRST(&group->members); 2158 if (!m) 2159 break; 2160 2161 TAILQ_REMOVE(&group->members, m, node); 2162 free(m); 2163 } 2164 2165 /* Schedule the group for deletion. */ 2166 s->groups_pending_delete[group_id] = 1; 2167 2168 return 0; 2169 } 2170 2171 int 2172 rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl, 2173 const char *selector_name, 2174 uint32_t group_id, 2175 uint32_t member_id, 2176 uint32_t member_weight) 2177 { 2178 struct selector *s; 2179 struct rte_swx_table_selector_group *group; 2180 struct rte_swx_table_selector_member *m; 2181 2182 if (!member_weight) 2183 return rte_swx_ctl_pipeline_selector_group_member_delete(ctl, 2184 selector_name, 2185 group_id, 2186 member_id); 2187 2188 /* Check input arguments. */ 2189 if (!ctl || !selector_name || !selector_name[0]) 2190 return -EINVAL; 2191 2192 s = selector_find(ctl, selector_name); 2193 if (!s || 2194 (group_id >= s->info.n_groups_max) || 2195 !s->groups_added[group_id] || 2196 s->groups_pending_delete[group_id]) 2197 return -EINVAL; 2198 2199 /* Initialize the pending group, if needed. */ 2200 if (!s->pending_groups[group_id]) { 2201 int status; 2202 2203 status = selector_group_duplicate_to_pending(s, group_id); 2204 if (status) 2205 return status; 2206 } 2207 2208 group = s->pending_groups[group_id]; 2209 2210 /* If this member is already in this group, then simply update its weight and return. */ 2211 TAILQ_FOREACH(m, &group->members, node) 2212 if (m->member_id == member_id) { 2213 m->member_weight = member_weight; 2214 return 0; 2215 } 2216 2217 /* Add new member to this group. */ 2218 m = calloc(1, sizeof(struct rte_swx_table_selector_member)); 2219 if (!m) 2220 return -ENOMEM; 2221 2222 m->member_id = member_id; 2223 m->member_weight = member_weight; 2224 2225 TAILQ_INSERT_TAIL(&group->members, m, node); 2226 2227 return 0; 2228 } 2229 2230 int 2231 rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl, 2232 const char *selector_name, 2233 uint32_t group_id __rte_unused, 2234 uint32_t member_id __rte_unused) 2235 { 2236 struct selector *s; 2237 struct rte_swx_table_selector_group *group; 2238 struct rte_swx_table_selector_member *m; 2239 2240 /* Check input arguments. */ 2241 if (!ctl || !selector_name || !selector_name[0]) 2242 return -EINVAL; 2243 2244 s = selector_find(ctl, selector_name); 2245 if (!s || 2246 (group_id >= s->info.n_groups_max) || 2247 !s->groups_added[group_id] || 2248 s->groups_pending_delete[group_id]) 2249 return -EINVAL; 2250 2251 /* Initialize the pending group, if needed. */ 2252 if (!s->pending_groups[group_id]) { 2253 int status; 2254 2255 status = selector_group_duplicate_to_pending(s, group_id); 2256 if (status) 2257 return status; 2258 } 2259 2260 group = s->pending_groups[group_id]; 2261 2262 /* Look for this member in the group and remove it, if found. */ 2263 TAILQ_FOREACH(m, &group->members, node) 2264 if (m->member_id == member_id) { 2265 TAILQ_REMOVE(&group->members, m, node); 2266 free(m); 2267 return 0; 2268 } 2269 2270 return 0; 2271 } 2272 2273 static int 2274 selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id) 2275 { 2276 struct selector *s = &ctl->selectors[selector_id]; 2277 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id]; 2278 uint32_t group_id; 2279 2280 /* Push pending group member changes (s->pending_groups[group_id]) to the selector table 2281 * mirror copy (ts_next->obj). 2282 */ 2283 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) { 2284 struct rte_swx_table_selector_group *group = s->pending_groups[group_id]; 2285 int status; 2286 2287 /* Skip this group if no change needed. */ 2288 if (!group) 2289 continue; 2290 2291 /* Apply the pending changes for the current group. */ 2292 status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group); 2293 if (status) 2294 return status; 2295 } 2296 2297 return 0; 2298 } 2299 2300 static void 2301 selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id) 2302 { 2303 struct selector *s = &ctl->selectors[selector_id]; 2304 uint32_t group_id; 2305 2306 /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group 2307 * records (s->groups[group_id). 2308 */ 2309 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) { 2310 struct rte_swx_table_selector_group *g = s->groups[group_id]; 2311 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id]; 2312 2313 /* Skip this group if no change needed. */ 2314 if (!gp) 2315 continue; 2316 2317 /* Transition the pending changes to stable. */ 2318 s->groups[group_id] = gp; 2319 s->pending_groups[group_id] = NULL; 2320 2321 /* Free the old group member list. */ 2322 if (!g) 2323 continue; 2324 2325 for ( ; ; ) { 2326 struct rte_swx_table_selector_member *m; 2327 2328 m = TAILQ_FIRST(&g->members); 2329 if (!m) 2330 break; 2331 2332 TAILQ_REMOVE(&g->members, m, node); 2333 free(m); 2334 } 2335 2336 free(g); 2337 } 2338 2339 /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to 2340 * s->groups_added[group_id]. 2341 */ 2342 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) 2343 if (s->groups_pending_delete[group_id]) { 2344 s->groups_added[group_id] = 0; 2345 s->groups_pending_delete[group_id] = 0; 2346 } 2347 } 2348 2349 static void 2350 selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id) 2351 { 2352 struct selector *s = &ctl->selectors[selector_id]; 2353 struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id]; 2354 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id]; 2355 uint32_t group_id; 2356 2357 /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */ 2358 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) { 2359 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id]; 2360 2361 if (gp) { 2362 ts_next->obj = ts->obj; 2363 break; 2364 } 2365 } 2366 } 2367 2368 static void 2369 selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id) 2370 { 2371 struct selector *s = &ctl->selectors[selector_id]; 2372 uint32_t group_id; 2373 2374 /* Discard any pending group member changes (s->pending_groups[group_id]). */ 2375 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) 2376 selector_pending_group_members_free(s, group_id); 2377 2378 /* Discard any pending group deletions. */ 2379 memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int)); 2380 } 2381 2382 static struct rte_swx_table_entry * 2383 learner_default_entry_alloc(struct learner *l) 2384 { 2385 struct rte_swx_table_entry *entry; 2386 2387 entry = calloc(1, sizeof(struct rte_swx_table_entry)); 2388 if (!entry) 2389 goto error; 2390 2391 /* action_data. */ 2392 if (l->action_data_size) { 2393 entry->action_data = calloc(1, l->action_data_size); 2394 if (!entry->action_data) 2395 goto error; 2396 } 2397 2398 return entry; 2399 2400 error: 2401 table_entry_free(entry); 2402 return NULL; 2403 } 2404 2405 static int 2406 learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl, 2407 uint32_t learner_id, 2408 struct rte_swx_table_entry *entry) 2409 { 2410 struct learner *l = &ctl->learners[learner_id]; 2411 struct action *a; 2412 uint32_t i; 2413 2414 CHECK(entry, EINVAL); 2415 2416 /* action_id. */ 2417 for (i = 0; i < l->info.n_actions; i++) 2418 if (entry->action_id == l->actions[i].action_id) 2419 break; 2420 2421 CHECK(i < l->info.n_actions, EINVAL); 2422 2423 /* action_data. */ 2424 a = &ctl->actions[entry->action_id]; 2425 CHECK(!(a->data_size && !entry->action_data), EINVAL); 2426 2427 return 0; 2428 } 2429 2430 static struct rte_swx_table_entry * 2431 learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl, 2432 uint32_t learner_id, 2433 struct rte_swx_table_entry *entry) 2434 { 2435 struct learner *l = &ctl->learners[learner_id]; 2436 struct rte_swx_table_entry *new_entry = NULL; 2437 struct action *a; 2438 uint32_t i; 2439 2440 if (!entry) 2441 goto error; 2442 2443 new_entry = calloc(1, sizeof(struct rte_swx_table_entry)); 2444 if (!new_entry) 2445 goto error; 2446 2447 /* action_id. */ 2448 for (i = 0; i < l->info.n_actions; i++) 2449 if (entry->action_id == l->actions[i].action_id) 2450 break; 2451 2452 if (i >= l->info.n_actions) 2453 goto error; 2454 2455 new_entry->action_id = entry->action_id; 2456 2457 /* action_data. */ 2458 a = &ctl->actions[entry->action_id]; 2459 if (a->data_size && !entry->action_data) 2460 goto error; 2461 2462 /* The table layer provisions a constant action data size per 2463 * entry, which should be the largest data size for all the 2464 * actions enabled for the current table, and attempts to copy 2465 * this many bytes each time a table entry is added, even if the 2466 * specific action requires less data or even no data at all, 2467 * hence we always have to allocate the max. 2468 */ 2469 new_entry->action_data = calloc(1, l->action_data_size); 2470 if (!new_entry->action_data) 2471 goto error; 2472 2473 if (a->data_size) 2474 memcpy(new_entry->action_data, entry->action_data, a->data_size); 2475 2476 return new_entry; 2477 2478 error: 2479 table_entry_free(new_entry); 2480 return NULL; 2481 } 2482 2483 int 2484 rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl, 2485 const char *learner_name, 2486 struct rte_swx_table_entry *entry) 2487 { 2488 struct learner *l; 2489 struct rte_swx_table_entry *new_entry; 2490 uint32_t learner_id; 2491 2492 CHECK(ctl, EINVAL); 2493 2494 CHECK(learner_name && learner_name[0], EINVAL); 2495 l = learner_find(ctl, learner_name); 2496 CHECK(l, EINVAL); 2497 learner_id = l - ctl->learners; 2498 CHECK(!l->info.default_action_is_const, EINVAL); 2499 2500 CHECK(entry, EINVAL); 2501 CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL); 2502 2503 CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL); 2504 2505 new_entry = learner_default_entry_duplicate(ctl, learner_id, entry); 2506 CHECK(new_entry, ENOMEM); 2507 2508 learner_pending_default_free(l); 2509 2510 l->pending_default = new_entry; 2511 return 0; 2512 } 2513 2514 static void 2515 learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id) 2516 { 2517 struct learner *l = &ctl->learners[learner_id]; 2518 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + 2519 ctl->info.n_selectors + learner_id]; 2520 struct action *a; 2521 uint8_t *action_data; 2522 uint64_t action_id; 2523 2524 /* Copy the pending default entry. */ 2525 if (!l->pending_default) 2526 return; 2527 2528 action_id = l->pending_default->action_id; 2529 action_data = l->pending_default->action_data; 2530 a = &ctl->actions[action_id]; 2531 2532 if (a->data_size) 2533 memcpy(ts_next->default_action_data, action_data, a->data_size); 2534 2535 ts_next->default_action_id = action_id; 2536 } 2537 2538 static void 2539 learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id) 2540 { 2541 struct learner *l = &ctl->learners[learner_id]; 2542 2543 /* Free up the pending default entry, as it is now part of the table. */ 2544 learner_pending_default_free(l); 2545 } 2546 2547 static void 2548 learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id) 2549 { 2550 struct learner *l = &ctl->learners[learner_id]; 2551 2552 /* Free up the pending default entry, as it is no longer going to be added to the table. */ 2553 learner_pending_default_free(l); 2554 } 2555 2556 int 2557 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail) 2558 { 2559 struct rte_swx_table_state *ts; 2560 int status = 0; 2561 uint32_t i; 2562 2563 CHECK(ctl, EINVAL); 2564 2565 /* Operate the changes on the current ts_next before it becomes the new ts. First, operate 2566 * all the changes that can fail; if no failure, then operate the changes that cannot fail. 2567 * We must be able to fully revert all the changes that can fail as if they never happened. 2568 */ 2569 for (i = 0; i < ctl->info.n_tables; i++) { 2570 status = table_rollfwd0(ctl, i, 0); 2571 if (status) 2572 goto rollback; 2573 } 2574 2575 for (i = 0; i < ctl->info.n_selectors; i++) { 2576 status = selector_rollfwd(ctl, i); 2577 if (status) 2578 goto rollback; 2579 } 2580 2581 /* Second, operate all the changes that cannot fail. Since nothing can fail from this point 2582 * onwards, the transaction is guaranteed to be successful. 2583 */ 2584 for (i = 0; i < ctl->info.n_tables; i++) 2585 table_rollfwd1(ctl, i); 2586 2587 for (i = 0; i < ctl->info.n_learners; i++) 2588 learner_rollfwd(ctl, i); 2589 2590 /* Swap the table state for the data plane. The current ts and ts_next 2591 * become the new ts_next and ts, respectively. 2592 */ 2593 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next); 2594 usleep(100); 2595 ts = ctl->ts; 2596 ctl->ts = ctl->ts_next; 2597 ctl->ts_next = ts; 2598 2599 /* Operate the changes on the current ts_next, which is the previous ts, in order to get 2600 * the current ts_next in sync with the current ts. Since the changes that can fail did 2601 * not fail on the previous ts_next, it is guaranteed that they will not fail on the 2602 * current ts_next, hence no error checking is needed. 2603 */ 2604 for (i = 0; i < ctl->info.n_tables; i++) { 2605 table_rollfwd0(ctl, i, 1); 2606 table_rollfwd1(ctl, i); 2607 table_rollfwd2(ctl, i); 2608 } 2609 2610 for (i = 0; i < ctl->info.n_selectors; i++) { 2611 selector_rollfwd(ctl, i); 2612 selector_rollfwd_finalize(ctl, i); 2613 } 2614 2615 for (i = 0; i < ctl->info.n_learners; i++) { 2616 learner_rollfwd(ctl, i); 2617 learner_rollfwd_finalize(ctl, i); 2618 } 2619 2620 return 0; 2621 2622 rollback: 2623 for (i = 0; i < ctl->info.n_tables; i++) { 2624 table_rollback(ctl, i); 2625 if (abort_on_fail) 2626 table_abort(ctl, i); 2627 } 2628 2629 for (i = 0; i < ctl->info.n_selectors; i++) { 2630 selector_rollback(ctl, i); 2631 if (abort_on_fail) 2632 selector_abort(ctl, i); 2633 } 2634 2635 if (abort_on_fail) 2636 for (i = 0; i < ctl->info.n_learners; i++) 2637 learner_abort(ctl, i); 2638 2639 return status; 2640 } 2641 2642 void 2643 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl) 2644 { 2645 uint32_t i; 2646 2647 if (!ctl) 2648 return; 2649 2650 for (i = 0; i < ctl->info.n_tables; i++) 2651 table_abort(ctl, i); 2652 2653 for (i = 0; i < ctl->info.n_selectors; i++) 2654 selector_abort(ctl, i); 2655 2656 for (i = 0; i < ctl->info.n_learners; i++) 2657 learner_abort(ctl, i); 2658 } 2659 2660 static int 2661 mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length) 2662 { 2663 uint32_t n_trailing_zeros = 0, n_ones = 0, i; 2664 2665 if (!mask) { 2666 *prefix_length = 0; 2667 return 0; 2668 } 2669 2670 /* Count trailing zero bits. */ 2671 for (i = 0; i < 64; i++) { 2672 if (mask & (1LLU << i)) 2673 break; 2674 2675 n_trailing_zeros++; 2676 } 2677 2678 /* Count the one bits that follow. */ 2679 for ( ; i < 64; i++) { 2680 if (!(mask & (1LLU << i))) 2681 break; 2682 2683 n_ones++; 2684 } 2685 2686 /* Check that no more one bits are present */ 2687 for ( ; i < 64; i++) 2688 if (mask & (1LLU << i)) 2689 return -EINVAL; 2690 2691 /* Check that the input mask is a prefix or the right length. */ 2692 if (n_ones + n_trailing_zeros != mask_length) 2693 return -EINVAL; 2694 2695 *prefix_length = n_ones; 2696 return 0; 2697 } 2698 2699 static int 2700 large_mask_to_prefix(uint8_t *mask, uint32_t n_mask_bytes, uint32_t *prefix_length) 2701 { 2702 uint32_t pl, i; 2703 2704 /* Check input arguments. */ 2705 if (!mask || !n_mask_bytes || !prefix_length) 2706 return -EINVAL; 2707 2708 /* Count leading bits of one. */ 2709 for (i = 0; i < n_mask_bytes * 8; i++) { 2710 uint32_t byte_id = i / 8; 2711 uint32_t bit_id = i & 7; 2712 2713 uint32_t byte = mask[byte_id]; 2714 uint32_t bit = byte & (1 << (7 - bit_id)); 2715 2716 if (!bit) 2717 break; 2718 } 2719 2720 /* Save the potential prefix length. */ 2721 pl = i; 2722 2723 /* Check that all remaining bits are zeros. */ 2724 for ( ; i < n_mask_bytes * 8; i++) { 2725 uint32_t byte_id = i / 8; 2726 uint32_t bit_id = i & 7; 2727 2728 uint32_t byte = mask[byte_id]; 2729 uint32_t bit = byte & (1 << (7 - bit_id)); 2730 2731 if (bit) 2732 break; 2733 } 2734 2735 if (i < n_mask_bytes * 8) 2736 return -EINVAL; 2737 2738 *prefix_length = pl; 2739 return 0; 2740 } 2741 2742 static int 2743 char_to_hex(char c, uint8_t *val) 2744 { 2745 if (c >= '0' && c <= '9') { 2746 *val = c - '0'; 2747 return 0; 2748 } 2749 2750 if (c >= 'A' && c <= 'F') { 2751 *val = c - 'A' + 10; 2752 return 0; 2753 } 2754 2755 if (c >= 'a' && c <= 'f') { 2756 *val = c - 'a' + 10; 2757 return 0; 2758 } 2759 2760 return -EINVAL; 2761 } 2762 2763 static int 2764 hex_string_parse(char *src, uint8_t *dst, uint32_t n_dst_bytes) 2765 { 2766 uint32_t i; 2767 2768 /* Check input arguments. */ 2769 if (!src || !src[0] || !dst || !n_dst_bytes) 2770 return -EINVAL; 2771 2772 /* Skip any leading "0x" or "0X" in the src string. */ 2773 if ((src[0] == '0') && (src[1] == 'x' || src[1] == 'X')) 2774 src += 2; 2775 2776 /* Convert each group of two hex characters in the src string to one byte in dst array. */ 2777 for (i = 0; i < n_dst_bytes; i++) { 2778 uint8_t a, b; 2779 int status; 2780 2781 status = char_to_hex(*src, &a); 2782 if (status) 2783 return status; 2784 src++; 2785 2786 status = char_to_hex(*src, &b); 2787 if (status) 2788 return status; 2789 src++; 2790 2791 dst[i] = a * 16 + b; 2792 } 2793 2794 /* Check for the end of the src string. */ 2795 if (*src) 2796 return -EINVAL; 2797 2798 return 0; 2799 } 2800 2801 static int 2802 table_entry_match_field_read(struct table *table, 2803 struct rte_swx_table_entry *entry, 2804 uint32_t mf_id, 2805 char *mf_val, 2806 char *mf_mask, 2807 int *lpm, 2808 uint32_t *lpm_prefix_length_max, 2809 uint32_t *lpm_prefix_length) 2810 { 2811 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[mf_id]; 2812 uint64_t val, mask = UINT64_MAX; 2813 uint32_t offset = (mf->offset - table->mf_first->offset) / 8; 2814 2815 /* 2816 * Mask. 2817 */ 2818 if (mf_mask) { 2819 /* Parse. */ 2820 mask = strtoull(mf_mask, &mf_mask, 0); 2821 if (mf_mask[0]) 2822 return -EINVAL; 2823 2824 /* LPM. */ 2825 if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) { 2826 int status; 2827 2828 *lpm = 1; 2829 2830 *lpm_prefix_length_max = mf->n_bits; 2831 2832 status = mask_to_prefix(mask, mf->n_bits, lpm_prefix_length); 2833 if (status) 2834 return status; 2835 } 2836 2837 /* Endianness conversion. */ 2838 if (mf->is_header) 2839 mask = field_hton(mask, mf->n_bits); 2840 } 2841 2842 /* Copy to entry. */ 2843 if (entry->key_mask) 2844 memcpy(&entry->key_mask[offset], (uint8_t *)&mask, mf->n_bits / 8); 2845 2846 /* 2847 * Value. 2848 */ 2849 /* Parse. */ 2850 val = strtoull(mf_val, &mf_val, 0); 2851 if (mf_val[0]) 2852 return -EINVAL; 2853 2854 /* Endianness conversion. */ 2855 if (mf->is_header) 2856 val = field_hton(val, mf->n_bits); 2857 2858 /* Copy to entry. */ 2859 memcpy(&entry->key[offset], (uint8_t *)&val, mf->n_bits / 8); 2860 2861 return 0; 2862 } 2863 2864 static int 2865 table_entry_action_argument_read(struct action *action, 2866 struct rte_swx_table_entry *entry, 2867 uint32_t arg_id, 2868 uint32_t arg_offset, 2869 char *arg_val) 2870 { 2871 struct rte_swx_ctl_action_arg_info *arg = &action->args[arg_id]; 2872 uint64_t val; 2873 2874 val = strtoull(arg_val, &arg_val, 0); 2875 if (arg_val[0]) 2876 return -EINVAL; 2877 2878 /* Endianness conversion. */ 2879 if (arg->is_network_byte_order) 2880 val = field_hton(val, arg->n_bits); 2881 2882 /* Copy to entry. */ 2883 memcpy(&entry->action_data[arg_offset], 2884 (uint8_t *)&val, 2885 arg->n_bits / 8); 2886 2887 return 0; 2888 } 2889 2890 static int 2891 table_entry_large_match_field_read(struct table *table, 2892 struct rte_swx_table_entry *entry, 2893 uint32_t mf_id, 2894 char *mf_val, 2895 char *mf_mask, 2896 int *lpm, 2897 uint32_t *lpm_prefix_length_max, 2898 uint32_t *lpm_prefix_length) 2899 { 2900 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[mf_id]; 2901 uint32_t offset = (mf->offset - table->mf_first->offset) / 8; 2902 int status; 2903 2904 /* 2905 * Mask. 2906 */ 2907 if (!entry->key_mask) 2908 goto value; 2909 2910 if (!mf_mask) { 2911 /* Set mask to all-ones. */ 2912 memset(&entry->key_mask[offset], 0xFF, mf->n_bits / 8); 2913 goto value; 2914 } 2915 2916 /* Parse. */ 2917 status = hex_string_parse(mf_mask, &entry->key_mask[offset], mf->n_bits / 8); 2918 if (status) 2919 return -EINVAL; 2920 2921 /* LPM. */ 2922 if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) { 2923 *lpm = 1; 2924 2925 *lpm_prefix_length_max = mf->n_bits; 2926 2927 status = large_mask_to_prefix(&entry->key_mask[offset], 2928 mf->n_bits / 8, 2929 lpm_prefix_length); 2930 if (status) 2931 return status; 2932 } 2933 2934 /* 2935 * Value. 2936 */ 2937 value: 2938 /* Parse. */ 2939 status = hex_string_parse(mf_val, &entry->key[offset], mf->n_bits / 8); 2940 if (status) 2941 return -EINVAL; 2942 2943 return 0; 2944 } 2945 2946 static int 2947 table_entry_large_action_argument_read(struct action *action, 2948 struct rte_swx_table_entry *entry, 2949 uint32_t arg_id, 2950 uint32_t arg_offset, 2951 char *arg_val) 2952 { 2953 struct rte_swx_ctl_action_arg_info *arg = &action->args[arg_id]; 2954 int status; 2955 2956 status = hex_string_parse(arg_val, &entry->action_data[arg_offset], arg->n_bits / 8); 2957 if (status) 2958 return -EINVAL; 2959 2960 return 0; 2961 } 2962 2963 static int 2964 token_is_comment(const char *token) 2965 { 2966 if ((token[0] == '#') || 2967 (token[0] == ';') || 2968 ((token[0] == '/') && (token[1] == '/'))) 2969 return 1; /* TRUE. */ 2970 2971 return 0; /* FALSE. */ 2972 } 2973 2974 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256 2975 2976 struct rte_swx_table_entry * 2977 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl, 2978 const char *table_name, 2979 const char *string, 2980 int *is_blank_or_comment) 2981 { 2982 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens; 2983 struct table *table; 2984 struct action *action; 2985 struct rte_swx_table_entry *entry = NULL; 2986 char *s0 = NULL, *s; 2987 uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i; 2988 int lpm = 0, blank_or_comment = 0; 2989 2990 /* Check input arguments. */ 2991 if (!ctl) 2992 goto error; 2993 2994 if (!table_name || !table_name[0]) 2995 goto error; 2996 2997 table = table_find(ctl, table_name); 2998 if (!table) 2999 goto error; 3000 3001 if (!string || !string[0]) 3002 goto error; 3003 3004 /* Memory allocation. */ 3005 s0 = strdup(string); 3006 if (!s0) 3007 goto error; 3008 3009 entry = table_entry_alloc(table); 3010 if (!entry) 3011 goto error; 3012 3013 /* Parse the string into tokens. */ 3014 for (s = s0; ; ) { 3015 char *token; 3016 3017 token = strtok_r(s, " \f\n\r\t\v", &s); 3018 if (!token || token_is_comment(token)) 3019 break; 3020 3021 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX) 3022 goto error; 3023 3024 token_array[n_tokens] = token; 3025 n_tokens++; 3026 } 3027 3028 if (!n_tokens) { 3029 blank_or_comment = 1; 3030 goto error; 3031 } 3032 3033 tokens = token_array; 3034 3035 /* 3036 * Match. 3037 */ 3038 if (!(n_tokens && !strcmp(tokens[0], "match"))) 3039 goto action; 3040 3041 if (n_tokens < 1 + table->info.n_match_fields) 3042 goto error; 3043 3044 for (i = 0; i < table->info.n_match_fields; i++) { 3045 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i]; 3046 char *mf_val = tokens[1 + i], *mf_mask = NULL; 3047 int status; 3048 3049 mf_mask = strchr(mf_val, '/'); 3050 if (mf_mask) { 3051 *mf_mask = 0; 3052 mf_mask++; 3053 } 3054 3055 if (mf->n_bits <= 64) 3056 status = table_entry_match_field_read(table, 3057 entry, 3058 i, 3059 mf_val, 3060 mf_mask, 3061 &lpm, 3062 &lpm_prefix_length_max, 3063 &lpm_prefix_length); 3064 else 3065 status = table_entry_large_match_field_read(table, 3066 entry, 3067 i, 3068 mf_val, 3069 mf_mask, 3070 &lpm, 3071 &lpm_prefix_length_max, 3072 &lpm_prefix_length); 3073 if (status) 3074 goto error; 3075 3076 } 3077 3078 tokens += 1 + table->info.n_match_fields; 3079 n_tokens -= 1 + table->info.n_match_fields; 3080 3081 /* 3082 * Match priority. 3083 */ 3084 if (n_tokens && !strcmp(tokens[0], "priority")) { 3085 char *priority = tokens[1]; 3086 uint32_t val; 3087 3088 if (n_tokens < 2) 3089 goto error; 3090 3091 /* Parse. */ 3092 val = strtoul(priority, &priority, 0); 3093 if (priority[0]) 3094 goto error; 3095 3096 /* Copy to entry. */ 3097 entry->key_priority = val; 3098 3099 tokens += 2; 3100 n_tokens -= 2; 3101 } 3102 3103 /* LPM. */ 3104 if (lpm) 3105 entry->key_priority = lpm_prefix_length_max - lpm_prefix_length; 3106 3107 /* 3108 * Action. 3109 */ 3110 action: 3111 if (!(n_tokens && !strcmp(tokens[0], "action"))) 3112 goto other; 3113 3114 if (n_tokens < 2) 3115 goto error; 3116 3117 action = action_find(ctl, tokens[1]); 3118 if (!action) 3119 goto error; 3120 3121 if (n_tokens < 2 + action->info.n_args * 2) 3122 goto error; 3123 3124 /* action_id. */ 3125 entry->action_id = action - ctl->actions; 3126 3127 /* action_data. */ 3128 for (i = 0; i < action->info.n_args; i++) { 3129 struct rte_swx_ctl_action_arg_info *arg = &action->args[i]; 3130 char *arg_name, *arg_val; 3131 int status; 3132 3133 arg_name = tokens[2 + i * 2]; 3134 arg_val = tokens[2 + i * 2 + 1]; 3135 3136 if (strcmp(arg_name, arg->name)) 3137 goto error; 3138 3139 if (arg->n_bits <= 64) 3140 status = table_entry_action_argument_read(action, 3141 entry, 3142 i, 3143 arg_offset, 3144 arg_val); 3145 else 3146 status = table_entry_large_action_argument_read(action, 3147 entry, 3148 i, 3149 arg_offset, 3150 arg_val); 3151 if (status) 3152 goto error; 3153 3154 arg_offset += arg->n_bits / 8; 3155 } 3156 3157 tokens += 2 + action->info.n_args * 2; 3158 n_tokens -= 2 + action->info.n_args * 2; 3159 3160 other: 3161 if (n_tokens) 3162 goto error; 3163 3164 free(s0); 3165 return entry; 3166 3167 error: 3168 table_entry_free(entry); 3169 free(s0); 3170 if (is_blank_or_comment) 3171 *is_blank_or_comment = blank_or_comment; 3172 return NULL; 3173 } 3174 3175 struct rte_swx_table_entry * 3176 rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl, 3177 const char *learner_name, 3178 const char *string, 3179 int *is_blank_or_comment) 3180 { 3181 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens; 3182 struct learner *l; 3183 struct action *action; 3184 struct rte_swx_table_entry *entry = NULL; 3185 char *s0 = NULL, *s; 3186 uint32_t n_tokens = 0, arg_offset = 0, i; 3187 int blank_or_comment = 0; 3188 3189 /* Check input arguments. */ 3190 if (!ctl) 3191 goto error; 3192 3193 if (!learner_name || !learner_name[0]) 3194 goto error; 3195 3196 l = learner_find(ctl, learner_name); 3197 if (!l) 3198 goto error; 3199 3200 if (!string || !string[0]) 3201 goto error; 3202 3203 /* Memory allocation. */ 3204 s0 = strdup(string); 3205 if (!s0) 3206 goto error; 3207 3208 entry = learner_default_entry_alloc(l); 3209 if (!entry) 3210 goto error; 3211 3212 /* Parse the string into tokens. */ 3213 for (s = s0; ; ) { 3214 char *token; 3215 3216 token = strtok_r(s, " \f\n\r\t\v", &s); 3217 if (!token || token_is_comment(token)) 3218 break; 3219 3220 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX) 3221 goto error; 3222 3223 token_array[n_tokens] = token; 3224 n_tokens++; 3225 } 3226 3227 if (!n_tokens) { 3228 blank_or_comment = 1; 3229 goto error; 3230 } 3231 3232 tokens = token_array; 3233 3234 /* 3235 * Action. 3236 */ 3237 if (!(n_tokens && !strcmp(tokens[0], "action"))) 3238 goto other; 3239 3240 if (n_tokens < 2) 3241 goto error; 3242 3243 action = action_find(ctl, tokens[1]); 3244 if (!action) 3245 goto error; 3246 3247 if (n_tokens < 2 + action->info.n_args * 2) 3248 goto error; 3249 3250 /* action_id. */ 3251 entry->action_id = action - ctl->actions; 3252 3253 /* action_data. */ 3254 for (i = 0; i < action->info.n_args; i++) { 3255 struct rte_swx_ctl_action_arg_info *arg = &action->args[i]; 3256 char *arg_name, *arg_val; 3257 uint64_t val; 3258 3259 arg_name = tokens[2 + i * 2]; 3260 arg_val = tokens[2 + i * 2 + 1]; 3261 3262 if (strcmp(arg_name, arg->name)) 3263 goto error; 3264 3265 val = strtoull(arg_val, &arg_val, 0); 3266 if (arg_val[0]) 3267 goto error; 3268 3269 /* Endianness conversion. */ 3270 if (arg->is_network_byte_order) 3271 val = field_hton(val, arg->n_bits); 3272 3273 /* Copy to entry. */ 3274 memcpy(&entry->action_data[arg_offset], 3275 (uint8_t *)&val, 3276 arg->n_bits / 8); 3277 3278 arg_offset += arg->n_bits / 8; 3279 } 3280 3281 tokens += 2 + action->info.n_args * 2; 3282 n_tokens -= 2 + action->info.n_args * 2; 3283 3284 other: 3285 if (n_tokens) 3286 goto error; 3287 3288 free(s0); 3289 return entry; 3290 3291 error: 3292 table_entry_free(entry); 3293 free(s0); 3294 if (is_blank_or_comment) 3295 *is_blank_or_comment = blank_or_comment; 3296 return NULL; 3297 } 3298 3299 static void 3300 table_entry_printf(FILE *f, 3301 struct rte_swx_ctl_pipeline *ctl, 3302 struct table *table, 3303 struct rte_swx_table_entry *entry) 3304 { 3305 struct action *action = &ctl->actions[entry->action_id]; 3306 uint32_t i; 3307 3308 fprintf(f, "match "); 3309 for (i = 0; i < table->params.key_size; i++) 3310 fprintf(f, "%02x", entry->key[i]); 3311 3312 if (entry->key_mask) { 3313 fprintf(f, "/"); 3314 for (i = 0; i < table->params.key_size; i++) 3315 fprintf(f, "%02x", entry->key_mask[i]); 3316 } 3317 3318 fprintf(f, " priority %u", entry->key_priority); 3319 3320 fprintf(f, " action %s ", action->info.name); 3321 for (i = 0; i < action->data_size; i++) 3322 fprintf(f, "%02x", entry->action_data[i]); 3323 3324 fprintf(f, "\n"); 3325 } 3326 3327 int 3328 rte_swx_ctl_pipeline_table_fprintf(FILE *f, 3329 struct rte_swx_ctl_pipeline *ctl, 3330 const char *table_name) 3331 { 3332 struct table *table; 3333 struct rte_swx_table_entry *entry; 3334 uint32_t n_entries = 0, i; 3335 3336 if (!f || !ctl || !table_name || !table_name[0]) 3337 return -EINVAL; 3338 3339 table = table_find(ctl, table_name); 3340 if (!table) 3341 return -EINVAL; 3342 3343 /* Table. */ 3344 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [", 3345 table->info.name, 3346 table->params.key_size, 3347 table->params.key_offset); 3348 3349 for (i = 0; i < table->params.key_size; i++) 3350 fprintf(f, "%02x", table->params.key_mask0[i]); 3351 3352 fprintf(f, "], action data size %u bytes\n", 3353 table->params.action_data_size); 3354 3355 /* Table entries. */ 3356 TAILQ_FOREACH(entry, &table->entries, node) { 3357 table_entry_printf(f, ctl, table, entry); 3358 n_entries++; 3359 } 3360 3361 TAILQ_FOREACH(entry, &table->pending_modify0, node) { 3362 table_entry_printf(f, ctl, table, entry); 3363 n_entries++; 3364 } 3365 3366 TAILQ_FOREACH(entry, &table->pending_delete, node) { 3367 table_entry_printf(f, ctl, table, entry); 3368 n_entries++; 3369 } 3370 3371 fprintf(f, "# Table %s currently has %u entries.\n", 3372 table_name, 3373 n_entries); 3374 return 0; 3375 } 3376 3377 int 3378 rte_swx_ctl_pipeline_selector_fprintf(FILE *f, 3379 struct rte_swx_ctl_pipeline *ctl, 3380 const char *selector_name) 3381 { 3382 struct selector *s; 3383 uint32_t group_id; 3384 3385 if (!f || !ctl || !selector_name || !selector_name[0]) 3386 return -EINVAL; 3387 3388 s = selector_find(ctl, selector_name); 3389 if (!s) 3390 return -EINVAL; 3391 3392 /* Selector. */ 3393 fprintf(f, "# Selector %s: max groups %u, max members per group %u\n", 3394 s->info.name, 3395 s->info.n_groups_max, 3396 s->info.n_members_per_group_max); 3397 3398 /* Groups. */ 3399 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) { 3400 struct rte_swx_table_selector_group *group = s->groups[group_id]; 3401 struct rte_swx_table_selector_member *m; 3402 uint32_t n_members = 0; 3403 3404 fprintf(f, "Group %u = [", group_id); 3405 3406 /* Non-empty group. */ 3407 if (group) 3408 TAILQ_FOREACH(m, &group->members, node) { 3409 fprintf(f, "%u:%u ", m->member_id, m->member_weight); 3410 n_members++; 3411 } 3412 3413 /* Empty group. */ 3414 if (!n_members) 3415 fprintf(f, "0:1 "); 3416 3417 fprintf(f, "]\n"); 3418 } 3419 3420 return 0; 3421 } 3422