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