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