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