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