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 if (ts->obj) 1050 rte_swx_table_selector_free(ts->obj); 1051 } 1052 1053 /* For each learner table, free its table state. */ 1054 learner_base_index = ctl->info.n_tables + ctl->info.n_selectors; 1055 for (i = 0; i < ctl->info.n_learners; i++) { 1056 struct rte_swx_table_state *ts = &ctl->ts_next[learner_base_index + i]; 1057 1058 /* Default action data. */ 1059 free(ts->default_action_data); 1060 } 1061 1062 free(ctl->ts_next); 1063 ctl->ts_next = NULL; 1064 } 1065 1066 static int 1067 table_state_create(struct rte_swx_ctl_pipeline *ctl) 1068 { 1069 uint32_t table_base_index, selector_base_index, learner_base_index, i; 1070 int status = 0; 1071 1072 ctl->ts_next = calloc(ctl->info.n_tables + ctl->info.n_selectors + ctl->info.n_learners, 1073 sizeof(struct rte_swx_table_state)); 1074 if (!ctl->ts_next) { 1075 status = -ENOMEM; 1076 goto error; 1077 } 1078 1079 /* Tables. */ 1080 table_base_index = 0; 1081 for (i = 0; i < ctl->info.n_tables; i++) { 1082 struct table *table = &ctl->tables[i]; 1083 struct rte_swx_table_state *ts = &ctl->ts[table_base_index + i]; 1084 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_base_index + i]; 1085 1086 /* Table object. */ 1087 if (!table->is_stub && table->ops.add) { 1088 ts_next->obj = table->ops.create(&table->params, 1089 &table->entries, 1090 table->info.args, 1091 ctl->numa_node); 1092 if (!ts_next->obj) { 1093 status = -ENODEV; 1094 goto error; 1095 } 1096 } 1097 1098 if (!table->is_stub && !table->ops.add) 1099 ts_next->obj = ts->obj; 1100 1101 /* Default action data: duplicate from current table state. */ 1102 ts_next->default_action_data = 1103 malloc(table->params.action_data_size); 1104 if (!ts_next->default_action_data) { 1105 status = -ENOMEM; 1106 goto error; 1107 } 1108 1109 memcpy(ts_next->default_action_data, 1110 ts->default_action_data, 1111 table->params.action_data_size); 1112 1113 ts_next->default_action_id = ts->default_action_id; 1114 } 1115 1116 /* Selector tables. */ 1117 selector_base_index = ctl->info.n_tables; 1118 for (i = 0; i < ctl->info.n_selectors; i++) { 1119 struct selector *s = &ctl->selectors[i]; 1120 struct rte_swx_table_state *ts_next = &ctl->ts_next[selector_base_index + i]; 1121 1122 /* Table object. */ 1123 ts_next->obj = rte_swx_table_selector_create(&s->params, NULL, ctl->numa_node); 1124 if (!ts_next->obj) { 1125 status = -ENODEV; 1126 goto error; 1127 } 1128 } 1129 1130 /* Learner tables. */ 1131 learner_base_index = ctl->info.n_tables + ctl->info.n_selectors; 1132 for (i = 0; i < ctl->info.n_learners; i++) { 1133 struct learner *l = &ctl->learners[i]; 1134 struct rte_swx_table_state *ts = &ctl->ts[learner_base_index + i]; 1135 struct rte_swx_table_state *ts_next = &ctl->ts_next[learner_base_index + i]; 1136 1137 /* Table object: duplicate from the current table state. */ 1138 ts_next->obj = ts->obj; 1139 1140 /* Default action data: duplicate from the current table state. */ 1141 ts_next->default_action_data = malloc(l->action_data_size); 1142 if (!ts_next->default_action_data) { 1143 status = -ENOMEM; 1144 goto error; 1145 } 1146 1147 memcpy(ts_next->default_action_data, 1148 ts->default_action_data, 1149 l->action_data_size); 1150 1151 ts_next->default_action_id = ts->default_action_id; 1152 } 1153 1154 return 0; 1155 1156 error: 1157 table_state_free(ctl); 1158 return status; 1159 } 1160 1161 void 1162 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl) 1163 { 1164 if (!ctl) 1165 return; 1166 1167 action_free(ctl); 1168 1169 table_state_free(ctl); 1170 1171 learner_free(ctl); 1172 1173 selector_free(ctl); 1174 1175 table_free(ctl); 1176 1177 free(ctl); 1178 } 1179 1180 struct rte_swx_ctl_pipeline * 1181 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p) 1182 { 1183 struct rte_swx_ctl_pipeline *ctl = NULL; 1184 uint32_t i; 1185 int status; 1186 1187 if (!p) 1188 goto error; 1189 1190 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline)); 1191 if (!ctl) 1192 goto error; 1193 1194 /* info. */ 1195 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info); 1196 if (status) 1197 goto error; 1198 1199 /* numa_node. */ 1200 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node); 1201 if (status) 1202 goto error; 1203 1204 /* p. */ 1205 ctl->p = p; 1206 1207 /* actions. */ 1208 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action)); 1209 if (!ctl->actions) 1210 goto error; 1211 1212 for (i = 0; i < ctl->info.n_actions; i++) { 1213 struct action *a = &ctl->actions[i]; 1214 uint32_t j; 1215 1216 /* info. */ 1217 status = rte_swx_ctl_action_info_get(p, i, &a->info); 1218 if (status) 1219 goto error; 1220 1221 /* args. */ 1222 a->args = calloc(a->info.n_args, 1223 sizeof(struct rte_swx_ctl_action_arg_info)); 1224 if (!a->args) 1225 goto error; 1226 1227 for (j = 0; j < a->info.n_args; j++) { 1228 status = rte_swx_ctl_action_arg_info_get(p, 1229 i, 1230 j, 1231 &a->args[j]); 1232 if (status) 1233 goto error; 1234 } 1235 1236 /* data_size. */ 1237 for (j = 0; j < a->info.n_args; j++) { 1238 struct rte_swx_ctl_action_arg_info *info = &a->args[j]; 1239 1240 a->data_size += info->n_bits; 1241 } 1242 1243 a->data_size = (a->data_size + 7) / 8; 1244 } 1245 1246 /* tables. */ 1247 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table)); 1248 if (!ctl->tables) 1249 goto error; 1250 1251 for (i = 0; i < ctl->info.n_tables; i++) { 1252 struct table *t = &ctl->tables[i]; 1253 1254 TAILQ_INIT(&t->entries); 1255 TAILQ_INIT(&t->pending_add); 1256 TAILQ_INIT(&t->pending_modify0); 1257 TAILQ_INIT(&t->pending_modify1); 1258 TAILQ_INIT(&t->pending_delete); 1259 } 1260 1261 for (i = 0; i < ctl->info.n_tables; i++) { 1262 struct table *t = &ctl->tables[i]; 1263 uint32_t j; 1264 1265 /* info. */ 1266 status = rte_swx_ctl_table_info_get(p, i, &t->info); 1267 if (status) 1268 goto error; 1269 1270 /* mf. */ 1271 t->mf = calloc(t->info.n_match_fields, 1272 sizeof(struct rte_swx_ctl_table_match_field_info)); 1273 if (!t->mf) 1274 goto error; 1275 1276 for (j = 0; j < t->info.n_match_fields; j++) { 1277 status = rte_swx_ctl_table_match_field_info_get(p, 1278 i, 1279 j, 1280 &t->mf[j]); 1281 if (status) 1282 goto error; 1283 } 1284 1285 /* actions. */ 1286 t->actions = calloc(t->info.n_actions, 1287 sizeof(struct rte_swx_ctl_table_action_info)); 1288 if (!t->actions) 1289 goto error; 1290 1291 for (j = 0; j < t->info.n_actions; j++) { 1292 status = rte_swx_ctl_table_action_info_get(p, 1293 i, 1294 j, 1295 &t->actions[j]); 1296 if (status || 1297 t->actions[j].action_id >= ctl->info.n_actions) 1298 goto error; 1299 } 1300 1301 /* ops, is_stub. */ 1302 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub); 1303 if (status) 1304 goto error; 1305 1306 if ((t->is_stub && t->info.n_match_fields) || 1307 (!t->is_stub && !t->info.n_match_fields)) 1308 goto error; 1309 1310 /* params. */ 1311 status = table_params_get(ctl, i); 1312 if (status) 1313 goto error; 1314 } 1315 1316 /* selector tables. */ 1317 ctl->selectors = calloc(ctl->info.n_selectors, sizeof(struct selector)); 1318 if (!ctl->selectors) 1319 goto error; 1320 1321 for (i = 0; i < ctl->info.n_selectors; i++) { 1322 struct selector *s = &ctl->selectors[i]; 1323 uint32_t j; 1324 1325 /* info. */ 1326 status = rte_swx_ctl_selector_info_get(p, i, &s->info); 1327 if (status) 1328 goto error; 1329 1330 /* group_id field. */ 1331 status = rte_swx_ctl_selector_group_id_field_info_get(p, 1332 i, 1333 &s->group_id_field); 1334 if (status) 1335 goto error; 1336 1337 /* selector fields. */ 1338 s->selector_fields = calloc(s->info.n_selector_fields, 1339 sizeof(struct rte_swx_ctl_table_match_field_info)); 1340 if (!s->selector_fields) 1341 goto error; 1342 1343 for (j = 0; j < s->info.n_selector_fields; j++) { 1344 status = rte_swx_ctl_selector_field_info_get(p, 1345 i, 1346 j, 1347 &s->selector_fields[j]); 1348 if (status) 1349 goto error; 1350 } 1351 1352 /* member_id field. */ 1353 status = rte_swx_ctl_selector_member_id_field_info_get(p, 1354 i, 1355 &s->member_id_field); 1356 if (status) 1357 goto error; 1358 1359 /* groups. */ 1360 s->groups = calloc(s->info.n_groups_max, 1361 sizeof(struct rte_swx_table_selector_group *)); 1362 if (!s->groups) 1363 goto error; 1364 1365 /* pending_groups. */ 1366 s->pending_groups = calloc(s->info.n_groups_max, 1367 sizeof(struct rte_swx_table_selector_group *)); 1368 if (!s->pending_groups) 1369 goto error; 1370 1371 /* groups_added. */ 1372 s->groups_added = calloc(s->info.n_groups_max, sizeof(int)); 1373 if (!s->groups_added) 1374 goto error; 1375 1376 /* groups_pending_delete. */ 1377 s->groups_pending_delete = calloc(s->info.n_groups_max, sizeof(int)); 1378 if (!s->groups_pending_delete) 1379 goto error; 1380 1381 /* params. */ 1382 status = selector_params_get(ctl, i); 1383 if (status) 1384 goto error; 1385 } 1386 1387 /* learner tables. */ 1388 ctl->learners = calloc(ctl->info.n_learners, sizeof(struct learner)); 1389 if (!ctl->learners) 1390 goto error; 1391 1392 for (i = 0; i < ctl->info.n_learners; i++) { 1393 struct learner *l = &ctl->learners[i]; 1394 uint32_t j; 1395 1396 /* info. */ 1397 status = rte_swx_ctl_learner_info_get(p, i, &l->info); 1398 if (status) 1399 goto error; 1400 1401 /* mf. */ 1402 l->mf = calloc(l->info.n_match_fields, 1403 sizeof(struct rte_swx_ctl_table_match_field_info)); 1404 if (!l->mf) 1405 goto error; 1406 1407 for (j = 0; j < l->info.n_match_fields; j++) { 1408 status = rte_swx_ctl_learner_match_field_info_get(p, 1409 i, 1410 j, 1411 &l->mf[j]); 1412 if (status) 1413 goto error; 1414 } 1415 1416 /* actions. */ 1417 l->actions = calloc(l->info.n_actions, 1418 sizeof(struct rte_swx_ctl_table_action_info)); 1419 if (!l->actions) 1420 goto error; 1421 1422 for (j = 0; j < l->info.n_actions; j++) { 1423 status = rte_swx_ctl_learner_action_info_get(p, 1424 i, 1425 j, 1426 &l->actions[j]); 1427 if (status || l->actions[j].action_id >= ctl->info.n_actions) 1428 goto error; 1429 } 1430 1431 /* action_data_size. */ 1432 l->action_data_size = learner_action_data_size_get(ctl, l); 1433 } 1434 1435 /* ts. */ 1436 status = rte_swx_pipeline_table_state_get(p, &ctl->ts); 1437 if (status) 1438 goto error; 1439 1440 /* ts_next. */ 1441 status = table_state_create(ctl); 1442 if (status) 1443 goto error; 1444 1445 return ctl; 1446 1447 error: 1448 rte_swx_ctl_pipeline_free(ctl); 1449 return NULL; 1450 } 1451 1452 int 1453 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl, 1454 const char *table_name, 1455 struct rte_swx_table_entry *entry) 1456 { 1457 struct table *table; 1458 struct rte_swx_table_entry *new_entry, *existing_entry; 1459 uint32_t table_id; 1460 1461 CHECK(ctl, EINVAL); 1462 CHECK(table_name && table_name[0], EINVAL); 1463 1464 table = table_find(ctl, table_name); 1465 CHECK(table, EINVAL); 1466 table_id = table - ctl->tables; 1467 1468 CHECK(entry, EINVAL); 1469 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL); 1470 1471 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1); 1472 CHECK(new_entry, ENOMEM); 1473 1474 /* The new entry is found in the table->entries list: 1475 * - Add the new entry to the table->pending_modify1 list; 1476 * - Move the existing entry from the table->entries list to the 1477 * table->pending_modify0 list. 1478 */ 1479 existing_entry = table_entries_find(table, entry); 1480 if (existing_entry) { 1481 TAILQ_INSERT_TAIL(&table->pending_modify1, 1482 new_entry, 1483 node); 1484 1485 TAILQ_REMOVE(&table->entries, 1486 existing_entry, 1487 node); 1488 1489 TAILQ_INSERT_TAIL(&table->pending_modify0, 1490 existing_entry, 1491 node); 1492 1493 return 0; 1494 } 1495 1496 /* The new entry is found in the table->pending_add list: 1497 * - Replace the entry in the table->pending_add list with the new entry 1498 * (and free the replaced entry). 1499 */ 1500 existing_entry = table_pending_add_find(table, entry); 1501 if (existing_entry) { 1502 TAILQ_INSERT_AFTER(&table->pending_add, 1503 existing_entry, 1504 new_entry, 1505 node); 1506 1507 TAILQ_REMOVE(&table->pending_add, 1508 existing_entry, 1509 node); 1510 1511 table_entry_free(existing_entry); 1512 1513 return 0; 1514 } 1515 1516 /* The new entry is found in the table->pending_modify1 list: 1517 * - Replace the entry in the table->pending_modify1 list with the new 1518 * entry (and free the replaced entry). 1519 */ 1520 existing_entry = table_pending_modify1_find(table, entry); 1521 if (existing_entry) { 1522 TAILQ_INSERT_AFTER(&table->pending_modify1, 1523 existing_entry, 1524 new_entry, 1525 node); 1526 1527 TAILQ_REMOVE(&table->pending_modify1, 1528 existing_entry, 1529 node); 1530 1531 table_entry_free(existing_entry); 1532 1533 return 0; 1534 } 1535 1536 /* The new entry is found in the table->pending_delete list: 1537 * - Add the new entry to the table->pending_modify1 list; 1538 * - Move the existing entry from the table->pending_delete list to the 1539 * table->pending_modify0 list. 1540 */ 1541 existing_entry = table_pending_delete_find(table, entry); 1542 if (existing_entry) { 1543 TAILQ_INSERT_TAIL(&table->pending_modify1, 1544 new_entry, 1545 node); 1546 1547 TAILQ_REMOVE(&table->pending_delete, 1548 existing_entry, 1549 node); 1550 1551 TAILQ_INSERT_TAIL(&table->pending_modify0, 1552 existing_entry, 1553 node); 1554 1555 return 0; 1556 } 1557 1558 /* The new entry is not found in any of the above lists: 1559 * - Add the new entry to the table->pending_add list. 1560 */ 1561 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node); 1562 1563 return 0; 1564 } 1565 1566 int 1567 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl, 1568 const char *table_name, 1569 struct rte_swx_table_entry *entry) 1570 { 1571 struct table *table; 1572 struct rte_swx_table_entry *existing_entry; 1573 uint32_t table_id; 1574 1575 CHECK(ctl, EINVAL); 1576 1577 CHECK(table_name && table_name[0], EINVAL); 1578 table = table_find(ctl, table_name); 1579 CHECK(table, EINVAL); 1580 table_id = table - ctl->tables; 1581 1582 CHECK(entry, EINVAL); 1583 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL); 1584 1585 /* The entry is found in the table->entries list: 1586 * - Move the existing entry from the table->entries list to to the 1587 * table->pending_delete list. 1588 */ 1589 existing_entry = table_entries_find(table, entry); 1590 if (existing_entry) { 1591 TAILQ_REMOVE(&table->entries, 1592 existing_entry, 1593 node); 1594 1595 TAILQ_INSERT_TAIL(&table->pending_delete, 1596 existing_entry, 1597 node); 1598 1599 return 0; 1600 } 1601 1602 /* The entry is found in the table->pending_add list: 1603 * - Remove the entry from the table->pending_add list and free it. 1604 */ 1605 existing_entry = table_pending_add_find(table, entry); 1606 if (existing_entry) { 1607 TAILQ_REMOVE(&table->pending_add, 1608 existing_entry, 1609 node); 1610 1611 table_entry_free(existing_entry); 1612 } 1613 1614 /* The entry is found in the table->pending_modify1 list: 1615 * - Free the entry in the table->pending_modify1 list; 1616 * - Move the existing entry from the table->pending_modify0 list to the 1617 * table->pending_delete list. 1618 */ 1619 existing_entry = table_pending_modify1_find(table, entry); 1620 if (existing_entry) { 1621 struct rte_swx_table_entry *real_existing_entry; 1622 1623 TAILQ_REMOVE(&table->pending_modify1, 1624 existing_entry, 1625 node); 1626 1627 table_entry_free(existing_entry); 1628 1629 real_existing_entry = table_pending_modify0_find(table, entry); 1630 CHECK(real_existing_entry, EINVAL); /* Coverity. */ 1631 1632 TAILQ_REMOVE(&table->pending_modify0, 1633 real_existing_entry, 1634 node); 1635 1636 TAILQ_INSERT_TAIL(&table->pending_delete, 1637 real_existing_entry, 1638 node); 1639 1640 return 0; 1641 } 1642 1643 /* The entry is found in the table->pending_delete list: 1644 * - Do nothing: the existing entry is already in the 1645 * table->pending_delete list, i.e. already marked for delete, so 1646 * simply keep it there as it is. 1647 */ 1648 1649 /* The entry is not found in any of the above lists: 1650 * - Do nothing: no existing entry to delete. 1651 */ 1652 1653 return 0; 1654 } 1655 1656 int 1657 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl, 1658 const char *table_name, 1659 struct rte_swx_table_entry *entry) 1660 { 1661 struct table *table; 1662 struct rte_swx_table_entry *new_entry; 1663 uint32_t table_id; 1664 1665 CHECK(ctl, EINVAL); 1666 1667 CHECK(table_name && table_name[0], EINVAL); 1668 table = table_find(ctl, table_name); 1669 CHECK(table, EINVAL); 1670 table_id = table - ctl->tables; 1671 CHECK(!table->info.default_action_is_const, EINVAL); 1672 1673 CHECK(entry, EINVAL); 1674 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL); 1675 1676 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1); 1677 CHECK(new_entry, ENOMEM); 1678 1679 table_pending_default_free(table); 1680 1681 table->pending_default = new_entry; 1682 return 0; 1683 } 1684 1685 1686 static void 1687 table_entry_list_free(struct rte_swx_table_entry_list *list) 1688 { 1689 for ( ; ; ) { 1690 struct rte_swx_table_entry *entry; 1691 1692 entry = TAILQ_FIRST(list); 1693 if (!entry) 1694 break; 1695 1696 TAILQ_REMOVE(list, entry, node); 1697 table_entry_free(entry); 1698 } 1699 } 1700 1701 static int 1702 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl, 1703 uint32_t table_id, 1704 struct rte_swx_table_entry_list *dst, 1705 struct rte_swx_table_entry_list *src) 1706 { 1707 struct rte_swx_table_entry *src_entry; 1708 1709 TAILQ_FOREACH(src_entry, src, node) { 1710 struct rte_swx_table_entry *dst_entry; 1711 1712 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1); 1713 if (!dst_entry) 1714 goto error; 1715 1716 TAILQ_INSERT_TAIL(dst, dst_entry, node); 1717 } 1718 1719 return 0; 1720 1721 error: 1722 table_entry_list_free(dst); 1723 return -ENOMEM; 1724 } 1725 1726 /* This commit stage contains all the operations that can fail; in case ANY of 1727 * them fails for ANY table, ALL of them are rolled back for ALL the tables. 1728 */ 1729 static int 1730 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl, 1731 uint32_t table_id, 1732 uint32_t after_swap) 1733 { 1734 struct table *table = &ctl->tables[table_id]; 1735 struct rte_swx_table_state *ts = &ctl->ts[table_id]; 1736 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id]; 1737 1738 if (table->is_stub || !table_is_update_pending(table, 0)) 1739 return 0; 1740 1741 /* 1742 * Current table supports incremental update. 1743 */ 1744 if (table->ops.add) { 1745 /* Reset counters. */ 1746 table->n_add = 0; 1747 table->n_modify = 0; 1748 table->n_delete = 0; 1749 1750 /* Add pending rules. */ 1751 struct rte_swx_table_entry *entry; 1752 1753 TAILQ_FOREACH(entry, &table->pending_add, node) { 1754 int status; 1755 1756 status = table->ops.add(ts_next->obj, entry); 1757 if (status) 1758 return status; 1759 1760 table->n_add++; 1761 } 1762 1763 /* Modify pending rules. */ 1764 TAILQ_FOREACH(entry, &table->pending_modify1, node) { 1765 int status; 1766 1767 status = table->ops.add(ts_next->obj, entry); 1768 if (status) 1769 return status; 1770 1771 table->n_modify++; 1772 } 1773 1774 /* Delete pending rules. */ 1775 TAILQ_FOREACH(entry, &table->pending_delete, node) { 1776 int status; 1777 1778 status = table->ops.del(ts_next->obj, entry); 1779 if (status) 1780 return status; 1781 1782 table->n_delete++; 1783 } 1784 1785 return 0; 1786 } 1787 1788 /* 1789 * Current table does NOT support incremental update. 1790 */ 1791 if (!after_swap) { 1792 struct rte_swx_table_entry_list list; 1793 int status; 1794 1795 /* Create updated list of entries included. */ 1796 TAILQ_INIT(&list); 1797 1798 status = table_entry_list_duplicate(ctl, 1799 table_id, 1800 &list, 1801 &table->entries); 1802 if (status) 1803 goto error; 1804 1805 status = table_entry_list_duplicate(ctl, 1806 table_id, 1807 &list, 1808 &table->pending_add); 1809 if (status) 1810 goto error; 1811 1812 status = table_entry_list_duplicate(ctl, 1813 table_id, 1814 &list, 1815 &table->pending_modify1); 1816 if (status) 1817 goto error; 1818 1819 /* Create new table object with the updates included. */ 1820 ts_next->obj = table->ops.create(&table->params, 1821 &list, 1822 table->info.args, 1823 ctl->numa_node); 1824 if (!ts_next->obj) { 1825 status = -ENODEV; 1826 goto error; 1827 } 1828 1829 table_entry_list_free(&list); 1830 1831 return 0; 1832 1833 error: 1834 table_entry_list_free(&list); 1835 return status; 1836 } 1837 1838 /* Free the old table object. */ 1839 if (ts_next->obj && table->ops.free) 1840 table->ops.free(ts_next->obj); 1841 1842 /* Copy over the new table object. */ 1843 ts_next->obj = ts->obj; 1844 1845 return 0; 1846 } 1847 1848 /* This commit stage contains all the operations that cannot fail. They are 1849 * executed only if the previous stage was successful for ALL the tables. Hence, 1850 * none of these operations has to be rolled back for ANY table. 1851 */ 1852 static void 1853 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 1854 { 1855 struct table *table = &ctl->tables[table_id]; 1856 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id]; 1857 struct action *a; 1858 uint8_t *action_data; 1859 uint64_t action_id; 1860 1861 /* Copy the pending default entry. */ 1862 if (!table->pending_default) 1863 return; 1864 1865 action_id = table->pending_default->action_id; 1866 action_data = table->pending_default->action_data; 1867 a = &ctl->actions[action_id]; 1868 1869 if (a->data_size) 1870 memcpy(ts_next->default_action_data, action_data, a->data_size); 1871 1872 ts_next->default_action_id = action_id; 1873 } 1874 1875 /* This last commit stage is simply finalizing a successful commit operation. 1876 * This stage is only executed if all the previous stages were successful. This 1877 * stage cannot fail. 1878 */ 1879 static void 1880 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 1881 { 1882 struct table *table = &ctl->tables[table_id]; 1883 1884 /* Move all the pending add entries to the table, as they are now part 1885 * of the table. 1886 */ 1887 table_pending_add_admit(table); 1888 1889 /* Move all the pending modify1 entries to table, are they are now part 1890 * of the table. Free up all the pending modify0 entries, as they are no 1891 * longer part of the table. 1892 */ 1893 table_pending_modify1_admit(table); 1894 table_pending_modify0_free(table); 1895 1896 /* Free up all the pending delete entries, as they are no longer part of 1897 * the table. 1898 */ 1899 table_pending_delete_free(table); 1900 1901 /* Free up the pending default entry, as it is now part of the table. */ 1902 table_pending_default_free(table); 1903 } 1904 1905 /* The rollback stage is only executed when the commit failed, i.e. ANY of the 1906 * commit operations that can fail did fail for ANY table. It reverts ALL the 1907 * tables to their state before the commit started, as if the commit never 1908 * happened. 1909 */ 1910 static void 1911 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 1912 { 1913 struct table *table = &ctl->tables[table_id]; 1914 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id]; 1915 1916 if (table->is_stub || !table_is_update_pending(table, 0)) 1917 return; 1918 1919 if (table->ops.add) { 1920 struct rte_swx_table_entry *entry; 1921 1922 /* Add back all the entries that were just deleted. */ 1923 TAILQ_FOREACH(entry, &table->pending_delete, node) { 1924 if (!table->n_delete) 1925 break; 1926 1927 table->ops.add(ts_next->obj, entry); 1928 table->n_delete--; 1929 } 1930 1931 /* Add back the old copy for all the entries that were just 1932 * modified. 1933 */ 1934 TAILQ_FOREACH(entry, &table->pending_modify0, node) { 1935 if (!table->n_modify) 1936 break; 1937 1938 table->ops.add(ts_next->obj, entry); 1939 table->n_modify--; 1940 } 1941 1942 /* Delete all the entries that were just added. */ 1943 TAILQ_FOREACH(entry, &table->pending_add, node) { 1944 if (!table->n_add) 1945 break; 1946 1947 table->ops.del(ts_next->obj, entry); 1948 table->n_add--; 1949 } 1950 } else { 1951 struct rte_swx_table_state *ts = &ctl->ts[table_id]; 1952 1953 /* Free the new table object, as update was cancelled. */ 1954 if (ts_next->obj && table->ops.free) 1955 table->ops.free(ts_next->obj); 1956 1957 /* Reinstate the old table object. */ 1958 ts_next->obj = ts->obj; 1959 } 1960 } 1961 1962 /* This stage is conditionally executed (as instructed by the user) after a 1963 * failed commit operation to remove ALL the pending work for ALL the tables. 1964 */ 1965 static void 1966 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 1967 { 1968 struct table *table = &ctl->tables[table_id]; 1969 1970 /* Free up all the pending add entries, as none of them is part of the 1971 * table. 1972 */ 1973 table_pending_add_free(table); 1974 1975 /* Free up all the pending modify1 entries, as none of them made it to 1976 * the table. Add back all the pending modify0 entries, as none of them 1977 * was deleted from the table. 1978 */ 1979 table_pending_modify1_free(table); 1980 table_pending_modify0_admit(table); 1981 1982 /* Add back all the pending delete entries, as none of them was deleted 1983 * from the table. 1984 */ 1985 table_pending_delete_admit(table); 1986 1987 /* Free up the pending default entry, as it is no longer going to be 1988 * added to the table. 1989 */ 1990 table_pending_default_free(table); 1991 } 1992 1993 int 1994 rte_swx_ctl_pipeline_selector_group_add(struct rte_swx_ctl_pipeline *ctl, 1995 const char *selector_name, 1996 uint32_t *group_id) 1997 { 1998 struct selector *s; 1999 uint32_t i; 2000 2001 /* Check input arguments. */ 2002 if (!ctl || !selector_name || !selector_name[0] || !group_id) 2003 return -EINVAL; 2004 2005 s = selector_find(ctl, selector_name); 2006 if (!s) 2007 return -EINVAL; 2008 2009 /* Find an unused group. */ 2010 for (i = 0; i < s->info.n_groups_max; i++) 2011 if (!s->groups_added[i]) { 2012 *group_id = i; 2013 s->groups_added[i] = 1; 2014 return 0; 2015 } 2016 2017 return -ENOSPC; 2018 } 2019 2020 int 2021 rte_swx_ctl_pipeline_selector_group_delete(struct rte_swx_ctl_pipeline *ctl, 2022 const char *selector_name, 2023 uint32_t group_id) 2024 { 2025 struct selector *s; 2026 struct rte_swx_table_selector_group *group; 2027 2028 /* Check input arguments. */ 2029 if (!ctl || !selector_name || !selector_name[0]) 2030 return -EINVAL; 2031 2032 s = selector_find(ctl, selector_name); 2033 if (!s || 2034 (group_id >= s->info.n_groups_max) || 2035 !s->groups_added[group_id]) 2036 return -EINVAL; 2037 2038 /* Check if this group is already scheduled for deletion. */ 2039 if (s->groups_pending_delete[group_id]) 2040 return 0; 2041 2042 /* Initialize the pending group, if needed. */ 2043 if (!s->pending_groups[group_id]) { 2044 int status; 2045 2046 status = selector_group_duplicate_to_pending(s, group_id); 2047 if (status) 2048 return status; 2049 } 2050 2051 group = s->pending_groups[group_id]; 2052 2053 /* Schedule removal of all the members from the current group. */ 2054 for ( ; ; ) { 2055 struct rte_swx_table_selector_member *m; 2056 2057 m = TAILQ_FIRST(&group->members); 2058 if (!m) 2059 break; 2060 2061 TAILQ_REMOVE(&group->members, m, node); 2062 free(m); 2063 } 2064 2065 /* Schedule the group for deletion. */ 2066 s->groups_pending_delete[group_id] = 1; 2067 2068 return 0; 2069 } 2070 2071 int 2072 rte_swx_ctl_pipeline_selector_group_member_add(struct rte_swx_ctl_pipeline *ctl, 2073 const char *selector_name, 2074 uint32_t group_id, 2075 uint32_t member_id, 2076 uint32_t member_weight) 2077 { 2078 struct selector *s; 2079 struct rte_swx_table_selector_group *group; 2080 struct rte_swx_table_selector_member *m; 2081 2082 if (!member_weight) 2083 return rte_swx_ctl_pipeline_selector_group_member_delete(ctl, 2084 selector_name, 2085 group_id, 2086 member_id); 2087 2088 /* Check input arguments. */ 2089 if (!ctl || !selector_name || !selector_name[0]) 2090 return -EINVAL; 2091 2092 s = selector_find(ctl, selector_name); 2093 if (!s || 2094 (group_id >= s->info.n_groups_max) || 2095 !s->groups_added[group_id] || 2096 s->groups_pending_delete[group_id]) 2097 return -EINVAL; 2098 2099 /* Initialize the pending group, if needed. */ 2100 if (!s->pending_groups[group_id]) { 2101 int status; 2102 2103 status = selector_group_duplicate_to_pending(s, group_id); 2104 if (status) 2105 return status; 2106 } 2107 2108 group = s->pending_groups[group_id]; 2109 2110 /* If this member is already in this group, then simply update its weight and return. */ 2111 TAILQ_FOREACH(m, &group->members, node) 2112 if (m->member_id == member_id) { 2113 m->member_weight = member_weight; 2114 return 0; 2115 } 2116 2117 /* Add new member to this group. */ 2118 m = calloc(1, sizeof(struct rte_swx_table_selector_member)); 2119 if (!m) 2120 return -ENOMEM; 2121 2122 m->member_id = member_id; 2123 m->member_weight = member_weight; 2124 2125 TAILQ_INSERT_TAIL(&group->members, m, node); 2126 2127 return 0; 2128 } 2129 2130 int 2131 rte_swx_ctl_pipeline_selector_group_member_delete(struct rte_swx_ctl_pipeline *ctl, 2132 const char *selector_name, 2133 uint32_t group_id __rte_unused, 2134 uint32_t member_id __rte_unused) 2135 { 2136 struct selector *s; 2137 struct rte_swx_table_selector_group *group; 2138 struct rte_swx_table_selector_member *m; 2139 2140 /* Check input arguments. */ 2141 if (!ctl || !selector_name || !selector_name[0]) 2142 return -EINVAL; 2143 2144 s = selector_find(ctl, selector_name); 2145 if (!s || 2146 (group_id >= s->info.n_groups_max) || 2147 !s->groups_added[group_id] || 2148 s->groups_pending_delete[group_id]) 2149 return -EINVAL; 2150 2151 /* Initialize the pending group, if needed. */ 2152 if (!s->pending_groups[group_id]) { 2153 int status; 2154 2155 status = selector_group_duplicate_to_pending(s, group_id); 2156 if (status) 2157 return status; 2158 } 2159 2160 group = s->pending_groups[group_id]; 2161 2162 /* Look for this member in the group and remove it, if found. */ 2163 TAILQ_FOREACH(m, &group->members, node) 2164 if (m->member_id == member_id) { 2165 TAILQ_REMOVE(&group->members, m, node); 2166 free(m); 2167 return 0; 2168 } 2169 2170 return 0; 2171 } 2172 2173 static int 2174 selector_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id) 2175 { 2176 struct selector *s = &ctl->selectors[selector_id]; 2177 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id]; 2178 uint32_t group_id; 2179 2180 /* Push pending group member changes (s->pending_groups[group_id]) to the selector table 2181 * mirror copy (ts_next->obj). 2182 */ 2183 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) { 2184 struct rte_swx_table_selector_group *group = s->pending_groups[group_id]; 2185 int status; 2186 2187 /* Skip this group if no change needed. */ 2188 if (!group) 2189 continue; 2190 2191 /* Apply the pending changes for the current group. */ 2192 status = rte_swx_table_selector_group_set(ts_next->obj, group_id, group); 2193 if (status) 2194 return status; 2195 } 2196 2197 return 0; 2198 } 2199 2200 static void 2201 selector_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id) 2202 { 2203 struct selector *s = &ctl->selectors[selector_id]; 2204 uint32_t group_id; 2205 2206 /* Commit pending group member changes (s->pending_groups[group_id]) to the stable group 2207 * records (s->groups[group_id). 2208 */ 2209 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) { 2210 struct rte_swx_table_selector_group *g = s->groups[group_id]; 2211 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id]; 2212 2213 /* Skip this group if no change needed. */ 2214 if (!gp) 2215 continue; 2216 2217 /* Transition the pending changes to stable. */ 2218 s->groups[group_id] = gp; 2219 s->pending_groups[group_id] = NULL; 2220 2221 /* Free the old group member list. */ 2222 if (!g) 2223 continue; 2224 2225 for ( ; ; ) { 2226 struct rte_swx_table_selector_member *m; 2227 2228 m = TAILQ_FIRST(&g->members); 2229 if (!m) 2230 break; 2231 2232 TAILQ_REMOVE(&g->members, m, node); 2233 free(m); 2234 } 2235 2236 free(g); 2237 } 2238 2239 /* Commit pending group validity changes (from s->groups_pending_delete[group_id] to 2240 * s->groups_added[group_id]. 2241 */ 2242 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) 2243 if (s->groups_pending_delete[group_id]) { 2244 s->groups_added[group_id] = 0; 2245 s->groups_pending_delete[group_id] = 0; 2246 } 2247 } 2248 2249 static void 2250 selector_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id) 2251 { 2252 struct selector *s = &ctl->selectors[selector_id]; 2253 struct rte_swx_table_state *ts = &ctl->ts[ctl->info.n_tables + selector_id]; 2254 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + selector_id]; 2255 uint32_t group_id; 2256 2257 /* Discard any previous changes to the selector table mirror copy (ts_next->obj). */ 2258 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) { 2259 struct rte_swx_table_selector_group *gp = s->pending_groups[group_id]; 2260 2261 if (gp) { 2262 ts_next->obj = ts->obj; 2263 break; 2264 } 2265 } 2266 } 2267 2268 static void 2269 selector_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t selector_id) 2270 { 2271 struct selector *s = &ctl->selectors[selector_id]; 2272 uint32_t group_id; 2273 2274 /* Discard any pending group member changes (s->pending_groups[group_id]). */ 2275 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) 2276 selector_pending_group_members_free(s, group_id); 2277 2278 /* Discard any pending group deletions. */ 2279 memset(s->groups_pending_delete, 0, s->info.n_groups_max * sizeof(int)); 2280 } 2281 2282 static struct rte_swx_table_entry * 2283 learner_default_entry_alloc(struct learner *l) 2284 { 2285 struct rte_swx_table_entry *entry; 2286 2287 entry = calloc(1, sizeof(struct rte_swx_table_entry)); 2288 if (!entry) 2289 goto error; 2290 2291 /* action_data. */ 2292 if (l->action_data_size) { 2293 entry->action_data = calloc(1, l->action_data_size); 2294 if (!entry->action_data) 2295 goto error; 2296 } 2297 2298 return entry; 2299 2300 error: 2301 table_entry_free(entry); 2302 return NULL; 2303 } 2304 2305 static int 2306 learner_default_entry_check(struct rte_swx_ctl_pipeline *ctl, 2307 uint32_t learner_id, 2308 struct rte_swx_table_entry *entry) 2309 { 2310 struct learner *l = &ctl->learners[learner_id]; 2311 struct action *a; 2312 uint32_t i; 2313 2314 CHECK(entry, EINVAL); 2315 2316 /* action_id. */ 2317 for (i = 0; i < l->info.n_actions; i++) 2318 if (entry->action_id == l->actions[i].action_id) 2319 break; 2320 2321 CHECK(i < l->info.n_actions, EINVAL); 2322 2323 /* action_data. */ 2324 a = &ctl->actions[entry->action_id]; 2325 CHECK(!(a->data_size && !entry->action_data), EINVAL); 2326 2327 return 0; 2328 } 2329 2330 static struct rte_swx_table_entry * 2331 learner_default_entry_duplicate(struct rte_swx_ctl_pipeline *ctl, 2332 uint32_t learner_id, 2333 struct rte_swx_table_entry *entry) 2334 { 2335 struct learner *l = &ctl->learners[learner_id]; 2336 struct rte_swx_table_entry *new_entry = NULL; 2337 struct action *a; 2338 uint32_t i; 2339 2340 if (!entry) 2341 goto error; 2342 2343 new_entry = calloc(1, sizeof(struct rte_swx_table_entry)); 2344 if (!new_entry) 2345 goto error; 2346 2347 /* action_id. */ 2348 for (i = 0; i < l->info.n_actions; i++) 2349 if (entry->action_id == l->actions[i].action_id) 2350 break; 2351 2352 if (i >= l->info.n_actions) 2353 goto error; 2354 2355 new_entry->action_id = entry->action_id; 2356 2357 /* action_data. */ 2358 a = &ctl->actions[entry->action_id]; 2359 if (a->data_size && !entry->action_data) 2360 goto error; 2361 2362 /* The table layer provisions a constant action data size per 2363 * entry, which should be the largest data size for all the 2364 * actions enabled for the current table, and attempts to copy 2365 * this many bytes each time a table entry is added, even if the 2366 * specific action requires less data or even no data at all, 2367 * hence we always have to allocate the max. 2368 */ 2369 new_entry->action_data = calloc(1, l->action_data_size); 2370 if (!new_entry->action_data) 2371 goto error; 2372 2373 if (a->data_size) 2374 memcpy(new_entry->action_data, entry->action_data, a->data_size); 2375 2376 return new_entry; 2377 2378 error: 2379 table_entry_free(new_entry); 2380 return NULL; 2381 } 2382 2383 int 2384 rte_swx_ctl_pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *ctl, 2385 const char *learner_name, 2386 struct rte_swx_table_entry *entry) 2387 { 2388 struct learner *l; 2389 struct rte_swx_table_entry *new_entry; 2390 uint32_t learner_id; 2391 2392 CHECK(ctl, EINVAL); 2393 2394 CHECK(learner_name && learner_name[0], EINVAL); 2395 l = learner_find(ctl, learner_name); 2396 CHECK(l, EINVAL); 2397 learner_id = l - ctl->learners; 2398 CHECK(!l->info.default_action_is_const, EINVAL); 2399 2400 CHECK(entry, EINVAL); 2401 CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL); 2402 2403 CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL); 2404 2405 new_entry = learner_default_entry_duplicate(ctl, learner_id, entry); 2406 CHECK(new_entry, ENOMEM); 2407 2408 learner_pending_default_free(l); 2409 2410 l->pending_default = new_entry; 2411 return 0; 2412 } 2413 2414 static void 2415 learner_rollfwd(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id) 2416 { 2417 struct learner *l = &ctl->learners[learner_id]; 2418 struct rte_swx_table_state *ts_next = &ctl->ts_next[ctl->info.n_tables + 2419 ctl->info.n_selectors + learner_id]; 2420 struct action *a; 2421 uint8_t *action_data; 2422 uint64_t action_id; 2423 2424 /* Copy the pending default entry. */ 2425 if (!l->pending_default) 2426 return; 2427 2428 action_id = l->pending_default->action_id; 2429 action_data = l->pending_default->action_data; 2430 a = &ctl->actions[action_id]; 2431 2432 if (a->data_size) 2433 memcpy(ts_next->default_action_data, action_data, a->data_size); 2434 2435 ts_next->default_action_id = action_id; 2436 } 2437 2438 static void 2439 learner_rollfwd_finalize(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id) 2440 { 2441 struct learner *l = &ctl->learners[learner_id]; 2442 2443 /* Free up the pending default entry, as it is now part of the table. */ 2444 learner_pending_default_free(l); 2445 } 2446 2447 static void 2448 learner_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t learner_id) 2449 { 2450 struct learner *l = &ctl->learners[learner_id]; 2451 2452 /* Free up the pending default entry, as it is no longer going to be added to the table. */ 2453 learner_pending_default_free(l); 2454 } 2455 2456 int 2457 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail) 2458 { 2459 struct rte_swx_table_state *ts; 2460 int status = 0; 2461 uint32_t i; 2462 2463 CHECK(ctl, EINVAL); 2464 2465 /* Operate the changes on the current ts_next before it becomes the new ts. First, operate 2466 * all the changes that can fail; if no failure, then operate the changes that cannot fail. 2467 * We must be able to fully revert all the changes that can fail as if they never happened. 2468 */ 2469 for (i = 0; i < ctl->info.n_tables; i++) { 2470 status = table_rollfwd0(ctl, i, 0); 2471 if (status) 2472 goto rollback; 2473 } 2474 2475 for (i = 0; i < ctl->info.n_selectors; i++) { 2476 status = selector_rollfwd(ctl, i); 2477 if (status) 2478 goto rollback; 2479 } 2480 2481 /* Second, operate all the changes that cannot fail. Since nothing can fail from this point 2482 * onwards, the transaction is guaranteed to be successful. 2483 */ 2484 for (i = 0; i < ctl->info.n_tables; i++) 2485 table_rollfwd1(ctl, i); 2486 2487 for (i = 0; i < ctl->info.n_learners; i++) 2488 learner_rollfwd(ctl, i); 2489 2490 /* Swap the table state for the data plane. The current ts and ts_next 2491 * become the new ts_next and ts, respectively. 2492 */ 2493 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next); 2494 usleep(100); 2495 ts = ctl->ts; 2496 ctl->ts = ctl->ts_next; 2497 ctl->ts_next = ts; 2498 2499 /* Operate the changes on the current ts_next, which is the previous ts, in order to get 2500 * the current ts_next in sync with the current ts. Since the changes that can fail did 2501 * not fail on the previous ts_next, it is guaranteed that they will not fail on the 2502 * current ts_next, hence no error checking is needed. 2503 */ 2504 for (i = 0; i < ctl->info.n_tables; i++) { 2505 table_rollfwd0(ctl, i, 1); 2506 table_rollfwd1(ctl, i); 2507 table_rollfwd2(ctl, i); 2508 } 2509 2510 for (i = 0; i < ctl->info.n_selectors; i++) { 2511 selector_rollfwd(ctl, i); 2512 selector_rollfwd_finalize(ctl, i); 2513 } 2514 2515 for (i = 0; i < ctl->info.n_learners; i++) { 2516 learner_rollfwd(ctl, i); 2517 learner_rollfwd_finalize(ctl, i); 2518 } 2519 2520 return 0; 2521 2522 rollback: 2523 for (i = 0; i < ctl->info.n_tables; i++) { 2524 table_rollback(ctl, i); 2525 if (abort_on_fail) 2526 table_abort(ctl, i); 2527 } 2528 2529 for (i = 0; i < ctl->info.n_selectors; i++) { 2530 selector_rollback(ctl, i); 2531 if (abort_on_fail) 2532 selector_abort(ctl, i); 2533 } 2534 2535 if (abort_on_fail) 2536 for (i = 0; i < ctl->info.n_learners; i++) 2537 learner_abort(ctl, i); 2538 2539 return status; 2540 } 2541 2542 void 2543 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl) 2544 { 2545 uint32_t i; 2546 2547 if (!ctl) 2548 return; 2549 2550 for (i = 0; i < ctl->info.n_tables; i++) 2551 table_abort(ctl, i); 2552 2553 for (i = 0; i < ctl->info.n_selectors; i++) 2554 selector_abort(ctl, i); 2555 2556 for (i = 0; i < ctl->info.n_learners; i++) 2557 learner_abort(ctl, i); 2558 } 2559 2560 static int 2561 mask_to_prefix(uint64_t mask, uint32_t mask_length, uint32_t *prefix_length) 2562 { 2563 uint32_t n_trailing_zeros = 0, n_ones = 0, i; 2564 2565 if (!mask) { 2566 *prefix_length = 0; 2567 return 0; 2568 } 2569 2570 /* Count trailing zero bits. */ 2571 for (i = 0; i < 64; i++) { 2572 if (mask & (1LLU << i)) 2573 break; 2574 2575 n_trailing_zeros++; 2576 } 2577 2578 /* Count the one bits that follow. */ 2579 for ( ; i < 64; i++) { 2580 if (!(mask & (1LLU << i))) 2581 break; 2582 2583 n_ones++; 2584 } 2585 2586 /* Check that no more one bits are present */ 2587 for ( ; i < 64; i++) 2588 if (mask & (1LLU << i)) 2589 return -EINVAL; 2590 2591 /* Check that the input mask is a prefix or the right length. */ 2592 if (n_ones + n_trailing_zeros != mask_length) 2593 return -EINVAL; 2594 2595 *prefix_length = n_ones; 2596 return 0; 2597 } 2598 2599 static int 2600 token_is_comment(const char *token) 2601 { 2602 if ((token[0] == '#') || 2603 (token[0] == ';') || 2604 ((token[0] == '/') && (token[1] == '/'))) 2605 return 1; /* TRUE. */ 2606 2607 return 0; /* FALSE. */ 2608 } 2609 2610 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256 2611 2612 struct rte_swx_table_entry * 2613 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl, 2614 const char *table_name, 2615 const char *string, 2616 int *is_blank_or_comment) 2617 { 2618 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens; 2619 struct table *table; 2620 struct action *action; 2621 struct rte_swx_table_entry *entry = NULL; 2622 char *s0 = NULL, *s; 2623 uint32_t n_tokens = 0, arg_offset = 0, lpm_prefix_length_max = 0, lpm_prefix_length = 0, i; 2624 int lpm = 0, blank_or_comment = 0; 2625 2626 /* Check input arguments. */ 2627 if (!ctl) 2628 goto error; 2629 2630 if (!table_name || !table_name[0]) 2631 goto error; 2632 2633 table = table_find(ctl, table_name); 2634 if (!table) 2635 goto error; 2636 2637 if (!string || !string[0]) 2638 goto error; 2639 2640 /* Memory allocation. */ 2641 s0 = strdup(string); 2642 if (!s0) 2643 goto error; 2644 2645 entry = table_entry_alloc(table); 2646 if (!entry) 2647 goto error; 2648 2649 /* Parse the string into tokens. */ 2650 for (s = s0; ; ) { 2651 char *token; 2652 2653 token = strtok_r(s, " \f\n\r\t\v", &s); 2654 if (!token || token_is_comment(token)) 2655 break; 2656 2657 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX) 2658 goto error; 2659 2660 token_array[n_tokens] = token; 2661 n_tokens++; 2662 } 2663 2664 if (!n_tokens) { 2665 blank_or_comment = 1; 2666 goto error; 2667 } 2668 2669 tokens = token_array; 2670 2671 /* 2672 * Match. 2673 */ 2674 if (!(n_tokens && !strcmp(tokens[0], "match"))) 2675 goto action; 2676 2677 if (n_tokens < 1 + table->info.n_match_fields) 2678 goto error; 2679 2680 for (i = 0; i < table->info.n_match_fields; i++) { 2681 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i]; 2682 char *mf_val = tokens[1 + i], *mf_mask = NULL; 2683 uint64_t val, mask = UINT64_MAX; 2684 uint32_t offset = (mf->offset - table->mf_first->offset) / 8; 2685 2686 /* 2687 * Mask. 2688 */ 2689 mf_mask = strchr(mf_val, '/'); 2690 if (mf_mask) { 2691 *mf_mask = 0; 2692 mf_mask++; 2693 2694 /* Parse. */ 2695 mask = strtoull(mf_mask, &mf_mask, 0); 2696 if (mf_mask[0]) 2697 goto error; 2698 2699 /* LPM. */ 2700 if (mf->match_type == RTE_SWX_TABLE_MATCH_LPM) { 2701 int status; 2702 2703 lpm = 1; 2704 2705 lpm_prefix_length_max = mf->n_bits; 2706 2707 status = mask_to_prefix(mask, mf->n_bits, &lpm_prefix_length); 2708 if (status) 2709 goto error; 2710 } 2711 2712 /* Endianness conversion. */ 2713 if (mf->is_header) 2714 mask = field_hton(mask, mf->n_bits); 2715 } 2716 2717 /* Copy to entry. */ 2718 if (entry->key_mask) 2719 memcpy(&entry->key_mask[offset], 2720 (uint8_t *)&mask, 2721 mf->n_bits / 8); 2722 2723 /* 2724 * Value. 2725 */ 2726 /* Parse. */ 2727 val = strtoull(mf_val, &mf_val, 0); 2728 if (mf_val[0]) 2729 goto error; 2730 2731 /* Endianness conversion. */ 2732 if (mf->is_header) 2733 val = field_hton(val, mf->n_bits); 2734 2735 /* Copy to entry. */ 2736 memcpy(&entry->key[offset], 2737 (uint8_t *)&val, 2738 mf->n_bits / 8); 2739 } 2740 2741 tokens += 1 + table->info.n_match_fields; 2742 n_tokens -= 1 + table->info.n_match_fields; 2743 2744 /* 2745 * Match priority. 2746 */ 2747 if (n_tokens && !strcmp(tokens[0], "priority")) { 2748 char *priority = tokens[1]; 2749 uint32_t val; 2750 2751 if (n_tokens < 2) 2752 goto error; 2753 2754 /* Parse. */ 2755 val = strtoul(priority, &priority, 0); 2756 if (priority[0]) 2757 goto error; 2758 2759 /* Copy to entry. */ 2760 entry->key_priority = val; 2761 2762 tokens += 2; 2763 n_tokens -= 2; 2764 } 2765 2766 /* LPM. */ 2767 if (lpm) 2768 entry->key_priority = lpm_prefix_length_max - lpm_prefix_length; 2769 2770 /* 2771 * Action. 2772 */ 2773 action: 2774 if (!(n_tokens && !strcmp(tokens[0], "action"))) 2775 goto other; 2776 2777 if (n_tokens < 2) 2778 goto error; 2779 2780 action = action_find(ctl, tokens[1]); 2781 if (!action) 2782 goto error; 2783 2784 if (n_tokens < 2 + action->info.n_args * 2) 2785 goto error; 2786 2787 /* action_id. */ 2788 entry->action_id = action - ctl->actions; 2789 2790 /* action_data. */ 2791 for (i = 0; i < action->info.n_args; i++) { 2792 struct rte_swx_ctl_action_arg_info *arg = &action->args[i]; 2793 char *arg_name, *arg_val; 2794 uint64_t val; 2795 2796 arg_name = tokens[2 + i * 2]; 2797 arg_val = tokens[2 + i * 2 + 1]; 2798 2799 if (strcmp(arg_name, arg->name)) 2800 goto error; 2801 2802 val = strtoull(arg_val, &arg_val, 0); 2803 if (arg_val[0]) 2804 goto error; 2805 2806 /* Endianness conversion. */ 2807 if (arg->is_network_byte_order) 2808 val = field_hton(val, arg->n_bits); 2809 2810 /* Copy to entry. */ 2811 memcpy(&entry->action_data[arg_offset], 2812 (uint8_t *)&val, 2813 arg->n_bits / 8); 2814 2815 arg_offset += arg->n_bits / 8; 2816 } 2817 2818 tokens += 2 + action->info.n_args * 2; 2819 n_tokens -= 2 + action->info.n_args * 2; 2820 2821 other: 2822 if (n_tokens) 2823 goto error; 2824 2825 free(s0); 2826 return entry; 2827 2828 error: 2829 table_entry_free(entry); 2830 free(s0); 2831 if (is_blank_or_comment) 2832 *is_blank_or_comment = blank_or_comment; 2833 return NULL; 2834 } 2835 2836 struct rte_swx_table_entry * 2837 rte_swx_ctl_pipeline_learner_default_entry_read(struct rte_swx_ctl_pipeline *ctl, 2838 const char *learner_name, 2839 const char *string, 2840 int *is_blank_or_comment) 2841 { 2842 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens; 2843 struct learner *l; 2844 struct action *action; 2845 struct rte_swx_table_entry *entry = NULL; 2846 char *s0 = NULL, *s; 2847 uint32_t n_tokens = 0, arg_offset = 0, i; 2848 int blank_or_comment = 0; 2849 2850 /* Check input arguments. */ 2851 if (!ctl) 2852 goto error; 2853 2854 if (!learner_name || !learner_name[0]) 2855 goto error; 2856 2857 l = learner_find(ctl, learner_name); 2858 if (!l) 2859 goto error; 2860 2861 if (!string || !string[0]) 2862 goto error; 2863 2864 /* Memory allocation. */ 2865 s0 = strdup(string); 2866 if (!s0) 2867 goto error; 2868 2869 entry = learner_default_entry_alloc(l); 2870 if (!entry) 2871 goto error; 2872 2873 /* Parse the string into tokens. */ 2874 for (s = s0; ; ) { 2875 char *token; 2876 2877 token = strtok_r(s, " \f\n\r\t\v", &s); 2878 if (!token || token_is_comment(token)) 2879 break; 2880 2881 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX) 2882 goto error; 2883 2884 token_array[n_tokens] = token; 2885 n_tokens++; 2886 } 2887 2888 if (!n_tokens) { 2889 blank_or_comment = 1; 2890 goto error; 2891 } 2892 2893 tokens = token_array; 2894 2895 /* 2896 * Action. 2897 */ 2898 if (!(n_tokens && !strcmp(tokens[0], "action"))) 2899 goto other; 2900 2901 if (n_tokens < 2) 2902 goto error; 2903 2904 action = action_find(ctl, tokens[1]); 2905 if (!action) 2906 goto error; 2907 2908 if (n_tokens < 2 + action->info.n_args * 2) 2909 goto error; 2910 2911 /* action_id. */ 2912 entry->action_id = action - ctl->actions; 2913 2914 /* action_data. */ 2915 for (i = 0; i < action->info.n_args; i++) { 2916 struct rte_swx_ctl_action_arg_info *arg = &action->args[i]; 2917 char *arg_name, *arg_val; 2918 uint64_t val; 2919 2920 arg_name = tokens[2 + i * 2]; 2921 arg_val = tokens[2 + i * 2 + 1]; 2922 2923 if (strcmp(arg_name, arg->name)) 2924 goto error; 2925 2926 val = strtoull(arg_val, &arg_val, 0); 2927 if (arg_val[0]) 2928 goto error; 2929 2930 /* Endianness conversion. */ 2931 if (arg->is_network_byte_order) 2932 val = field_hton(val, arg->n_bits); 2933 2934 /* Copy to entry. */ 2935 memcpy(&entry->action_data[arg_offset], 2936 (uint8_t *)&val, 2937 arg->n_bits / 8); 2938 2939 arg_offset += arg->n_bits / 8; 2940 } 2941 2942 tokens += 2 + action->info.n_args * 2; 2943 n_tokens -= 2 + action->info.n_args * 2; 2944 2945 other: 2946 if (n_tokens) 2947 goto error; 2948 2949 free(s0); 2950 return entry; 2951 2952 error: 2953 table_entry_free(entry); 2954 free(s0); 2955 if (is_blank_or_comment) 2956 *is_blank_or_comment = blank_or_comment; 2957 return NULL; 2958 } 2959 2960 static void 2961 table_entry_printf(FILE *f, 2962 struct rte_swx_ctl_pipeline *ctl, 2963 struct table *table, 2964 struct rte_swx_table_entry *entry) 2965 { 2966 struct action *action = &ctl->actions[entry->action_id]; 2967 uint32_t i; 2968 2969 fprintf(f, "match "); 2970 for (i = 0; i < table->params.key_size; i++) 2971 fprintf(f, "%02x", entry->key[i]); 2972 2973 if (entry->key_mask) { 2974 fprintf(f, "/"); 2975 for (i = 0; i < table->params.key_size; i++) 2976 fprintf(f, "%02x", entry->key_mask[i]); 2977 } 2978 2979 fprintf(f, " priority %u", entry->key_priority); 2980 2981 fprintf(f, " action %s ", action->info.name); 2982 for (i = 0; i < action->data_size; i++) 2983 fprintf(f, "%02x", entry->action_data[i]); 2984 2985 fprintf(f, "\n"); 2986 } 2987 2988 int 2989 rte_swx_ctl_pipeline_table_fprintf(FILE *f, 2990 struct rte_swx_ctl_pipeline *ctl, 2991 const char *table_name) 2992 { 2993 struct table *table; 2994 struct rte_swx_table_entry *entry; 2995 uint32_t n_entries = 0, i; 2996 2997 if (!f || !ctl || !table_name || !table_name[0]) 2998 return -EINVAL; 2999 3000 table = table_find(ctl, table_name); 3001 if (!table) 3002 return -EINVAL; 3003 3004 /* Table. */ 3005 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [", 3006 table->info.name, 3007 table->params.key_size, 3008 table->params.key_offset); 3009 3010 for (i = 0; i < table->params.key_size; i++) 3011 fprintf(f, "%02x", table->params.key_mask0[i]); 3012 3013 fprintf(f, "], action data size %u bytes\n", 3014 table->params.action_data_size); 3015 3016 /* Table entries. */ 3017 TAILQ_FOREACH(entry, &table->entries, node) { 3018 table_entry_printf(f, ctl, table, entry); 3019 n_entries++; 3020 } 3021 3022 TAILQ_FOREACH(entry, &table->pending_modify0, node) { 3023 table_entry_printf(f, ctl, table, entry); 3024 n_entries++; 3025 } 3026 3027 TAILQ_FOREACH(entry, &table->pending_delete, node) { 3028 table_entry_printf(f, ctl, table, entry); 3029 n_entries++; 3030 } 3031 3032 fprintf(f, "# Table %s currently has %u entries.\n", 3033 table_name, 3034 n_entries); 3035 return 0; 3036 } 3037 3038 int 3039 rte_swx_ctl_pipeline_selector_fprintf(FILE *f, 3040 struct rte_swx_ctl_pipeline *ctl, 3041 const char *selector_name) 3042 { 3043 struct selector *s; 3044 uint32_t group_id; 3045 3046 if (!f || !ctl || !selector_name || !selector_name[0]) 3047 return -EINVAL; 3048 3049 s = selector_find(ctl, selector_name); 3050 if (!s) 3051 return -EINVAL; 3052 3053 /* Selector. */ 3054 fprintf(f, "# Selector %s: max groups %u, max members per group %u\n", 3055 s->info.name, 3056 s->info.n_groups_max, 3057 s->info.n_members_per_group_max); 3058 3059 /* Groups. */ 3060 for (group_id = 0; group_id < s->info.n_groups_max; group_id++) { 3061 struct rte_swx_table_selector_group *group = s->groups[group_id]; 3062 struct rte_swx_table_selector_member *m; 3063 uint32_t n_members = 0; 3064 3065 fprintf(f, "Group %u = [", group_id); 3066 3067 /* Non-empty group. */ 3068 if (group) 3069 TAILQ_FOREACH(m, &group->members, node) { 3070 fprintf(f, "%u:%u ", m->member_id, m->member_weight); 3071 n_members++; 3072 } 3073 3074 /* Empty group. */ 3075 if (!n_members) 3076 fprintf(f, "0:1 "); 3077 3078 fprintf(f, "]\n"); 3079 } 3080 3081 return 0; 3082 } 3083