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_ctl.h" 14 15 #define CHECK(condition, err_code) \ 16 do { \ 17 if (!(condition)) \ 18 return -(err_code); \ 19 } while (0) 20 21 #define ntoh64(x) rte_be_to_cpu_64(x) 22 #define hton64(x) rte_cpu_to_be_64(x) 23 24 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN 25 #define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits))) 26 #define field_hton(val, n_bits) (hton64((val) << (64 - n_bits))) 27 #else 28 #define field_ntoh(val, n_bits) (val) 29 #define field_hton(val, n_bits) (val) 30 #endif 31 32 struct action { 33 struct rte_swx_ctl_action_info info; 34 struct rte_swx_ctl_action_arg_info *args; 35 uint32_t data_size; 36 }; 37 38 struct table { 39 struct rte_swx_ctl_table_info info; 40 struct rte_swx_ctl_table_match_field_info *mf; 41 42 /* Match field with the smallest offset. */ 43 struct rte_swx_ctl_table_match_field_info *mf_first; 44 45 /* Match field with the biggest offset. */ 46 struct rte_swx_ctl_table_match_field_info *mf_last; 47 48 struct rte_swx_ctl_table_action_info *actions; 49 struct rte_swx_table_ops ops; 50 struct rte_swx_table_params params; 51 52 /* Set of "stable" keys: these keys are currently part of the table; 53 * these keys will be preserved with no action data changes after the 54 * next commit. 55 */ 56 struct rte_swx_table_entry_list entries; 57 58 /* Set of new keys: these keys are currently NOT part of the table; 59 * these keys will be added to the table on the next commit, if 60 * the commit operation is successful. 61 */ 62 struct rte_swx_table_entry_list pending_add; 63 64 /* Set of keys to be modified: these keys are currently part of the 65 * table; these keys are still going to be part of the table after the 66 * next commit, but their action data will be modified if the commit 67 * operation is successful. The modify0 list contains the keys with the 68 * current action data, the modify1 list contains the keys with the 69 * modified action data. 70 */ 71 struct rte_swx_table_entry_list pending_modify0; 72 struct rte_swx_table_entry_list pending_modify1; 73 74 /* Set of keys to be deleted: these keys are currently part of the 75 * table; these keys are to be deleted from the table on the next 76 * commit, if the commit operation is successful. 77 */ 78 struct rte_swx_table_entry_list pending_delete; 79 80 /* The pending default action: this is NOT the current default action; 81 * this will be the new default action after the next commit, if the 82 * next commit operation is successful. 83 */ 84 struct rte_swx_table_entry *pending_default; 85 86 int is_stub; 87 uint32_t n_add; 88 uint32_t n_modify; 89 uint32_t n_delete; 90 }; 91 92 struct rte_swx_ctl_pipeline { 93 struct rte_swx_ctl_pipeline_info info; 94 struct rte_swx_pipeline *p; 95 struct action *actions; 96 struct table *tables; 97 struct rte_swx_table_state *ts; 98 struct rte_swx_table_state *ts_next; 99 int numa_node; 100 }; 101 102 static struct action * 103 action_find(struct rte_swx_ctl_pipeline *ctl, const char *action_name) 104 { 105 uint32_t i; 106 107 for (i = 0; i < ctl->info.n_actions; i++) { 108 struct action *a = &ctl->actions[i]; 109 110 if (!strcmp(action_name, a->info.name)) 111 return a; 112 } 113 114 return NULL; 115 } 116 117 static void 118 action_free(struct rte_swx_ctl_pipeline *ctl) 119 { 120 uint32_t i; 121 122 if (!ctl->actions) 123 return; 124 125 for (i = 0; i < ctl->info.n_actions; i++) { 126 struct action *action = &ctl->actions[i]; 127 128 free(action->args); 129 } 130 131 free(ctl->actions); 132 ctl->actions = NULL; 133 } 134 135 static struct table * 136 table_find(struct rte_swx_ctl_pipeline *ctl, const char *table_name) 137 { 138 uint32_t i; 139 140 for (i = 0; i < ctl->info.n_tables; i++) { 141 struct table *table = &ctl->tables[i]; 142 143 if (!strcmp(table_name, table->info.name)) 144 return table; 145 } 146 147 return NULL; 148 } 149 150 static int 151 table_params_get(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 152 { 153 struct table *table = &ctl->tables[table_id]; 154 struct rte_swx_ctl_table_match_field_info *first = NULL, *last = NULL; 155 uint8_t *key_mask = NULL; 156 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD; 157 uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i; 158 159 if (table->info.n_match_fields) { 160 uint32_t n_match_fields_em = 0, i; 161 162 /* Find first (smallest offset) and last (biggest offset) match fields. */ 163 first = &table->mf[0]; 164 last = &table->mf[0]; 165 166 for (i = 1; i < table->info.n_match_fields; i++) { 167 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i]; 168 169 if (f->offset < first->offset) 170 first = f; 171 172 if (f->offset > last->offset) 173 last = f; 174 } 175 176 /* match_type. */ 177 for (i = 0; i < table->info.n_match_fields; i++) { 178 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i]; 179 180 if (f->match_type == RTE_SWX_TABLE_MATCH_EXACT) 181 n_match_fields_em++; 182 } 183 184 if (n_match_fields_em == table->info.n_match_fields) 185 match_type = RTE_SWX_TABLE_MATCH_EXACT; 186 else if ((n_match_fields_em == table->info.n_match_fields - 1) && 187 (last->match_type == RTE_SWX_TABLE_MATCH_LPM)) 188 match_type = RTE_SWX_TABLE_MATCH_LPM; 189 190 /* key_offset. */ 191 key_offset = first->offset / 8; 192 193 /* key_size. */ 194 key_size = (last->offset + last->n_bits - first->offset) / 8; 195 196 /* key_mask. */ 197 key_mask = calloc(1, key_size); 198 CHECK(key_mask, ENOMEM); 199 200 for (i = 0; i < table->info.n_match_fields; i++) { 201 struct rte_swx_ctl_table_match_field_info *f = &table->mf[i]; 202 uint32_t start; 203 size_t size; 204 205 start = (f->offset - first->offset) / 8; 206 size = f->n_bits / 8; 207 208 memset(&key_mask[start], 0xFF, size); 209 } 210 } 211 212 /* action_data_size. */ 213 for (i = 0; i < table->info.n_actions; i++) { 214 uint32_t action_id = table->actions[i].action_id; 215 struct action *a = &ctl->actions[action_id]; 216 217 if (a->data_size > action_data_size) 218 action_data_size = a->data_size; 219 } 220 221 /* Fill in. */ 222 table->params.match_type = match_type; 223 table->params.key_size = key_size; 224 table->params.key_offset = key_offset; 225 table->params.key_mask0 = key_mask; 226 table->params.action_data_size = action_data_size; 227 table->params.n_keys_max = table->info.size; 228 229 table->mf_first = first; 230 table->mf_last = last; 231 232 return 0; 233 } 234 235 static void 236 table_entry_free(struct rte_swx_table_entry *entry) 237 { 238 if (!entry) 239 return; 240 241 free(entry->key); 242 free(entry->key_mask); 243 free(entry->action_data); 244 free(entry); 245 } 246 247 static struct rte_swx_table_entry * 248 table_entry_alloc(struct table *table) 249 { 250 struct rte_swx_table_entry *entry; 251 252 entry = calloc(1, sizeof(struct rte_swx_table_entry)); 253 if (!entry) 254 goto error; 255 256 /* key, key_mask. */ 257 if (!table->is_stub) { 258 entry->key = calloc(1, table->params.key_size); 259 if (!entry->key) 260 goto error; 261 262 if (table->params.match_type != RTE_SWX_TABLE_MATCH_EXACT) { 263 entry->key_mask = calloc(1, table->params.key_size); 264 if (!entry->key_mask) 265 goto error; 266 } 267 } 268 269 /* action_data. */ 270 if (table->params.action_data_size) { 271 entry->action_data = calloc(1, table->params.action_data_size); 272 if (!entry->action_data) 273 goto error; 274 } 275 276 return entry; 277 278 error: 279 table_entry_free(entry); 280 return NULL; 281 } 282 283 static int 284 table_entry_key_check_em(struct table *table, struct rte_swx_table_entry *entry) 285 { 286 uint8_t *key_mask0 = table->params.key_mask0; 287 uint32_t key_size = table->params.key_size, i; 288 289 if (!entry->key_mask) 290 return 0; 291 292 for (i = 0; i < key_size; i++) { 293 uint8_t km0 = key_mask0[i]; 294 uint8_t km = entry->key_mask[i]; 295 296 if ((km & km0) != km0) 297 return -EINVAL; 298 } 299 300 return 0; 301 } 302 303 static int 304 table_entry_check(struct rte_swx_ctl_pipeline *ctl, 305 uint32_t table_id, 306 struct rte_swx_table_entry *entry, 307 int key_check, 308 int data_check) 309 { 310 struct table *table = &ctl->tables[table_id]; 311 int status; 312 313 CHECK(entry, EINVAL); 314 315 if (key_check) { 316 if (table->is_stub) { 317 /* key. */ 318 CHECK(!entry->key, EINVAL); 319 320 /* key_mask. */ 321 CHECK(!entry->key_mask, EINVAL); 322 } else { 323 /* key. */ 324 CHECK(entry->key, EINVAL); 325 326 /* key_mask. */ 327 switch (table->params.match_type) { 328 case RTE_SWX_TABLE_MATCH_WILDCARD: 329 break; 330 331 case RTE_SWX_TABLE_MATCH_LPM: 332 /* TBD Check that key mask is prefix. */ 333 break; 334 335 case RTE_SWX_TABLE_MATCH_EXACT: 336 status = table_entry_key_check_em(table, entry); 337 if (status) 338 return status; 339 break; 340 341 default: 342 CHECK(0, EINVAL); 343 } 344 } 345 } 346 347 if (data_check) { 348 struct action *a; 349 uint32_t i; 350 351 /* action_id. */ 352 for (i = 0; i < table->info.n_actions; i++) 353 if (entry->action_id == table->actions[i].action_id) 354 break; 355 356 CHECK(i < table->info.n_actions, EINVAL); 357 358 /* action_data. */ 359 a = &ctl->actions[entry->action_id]; 360 CHECK(!(a->data_size && !entry->action_data), EINVAL); 361 } 362 363 return 0; 364 } 365 366 static struct rte_swx_table_entry * 367 table_entry_duplicate(struct rte_swx_ctl_pipeline *ctl, 368 uint32_t table_id, 369 struct rte_swx_table_entry *entry, 370 int key_duplicate, 371 int data_duplicate) 372 { 373 struct table *table = &ctl->tables[table_id]; 374 struct rte_swx_table_entry *new_entry = NULL; 375 376 if (!entry) 377 goto error; 378 379 new_entry = calloc(1, sizeof(struct rte_swx_table_entry)); 380 if (!new_entry) 381 goto error; 382 383 if (key_duplicate && !table->is_stub) { 384 /* key. */ 385 if (!entry->key) 386 goto error; 387 388 new_entry->key = malloc(table->params.key_size); 389 if (!new_entry->key) 390 goto error; 391 392 memcpy(new_entry->key, entry->key, table->params.key_size); 393 394 /* key_signature. */ 395 new_entry->key_signature = entry->key_signature; 396 397 /* key_mask. */ 398 if (entry->key_mask) { 399 new_entry->key_mask = malloc(table->params.key_size); 400 if (!new_entry->key_mask) 401 goto error; 402 403 memcpy(new_entry->key_mask, 404 entry->key_mask, 405 table->params.key_size); 406 } 407 408 /* key_priority. */ 409 new_entry->key_priority = entry->key_priority; 410 } 411 412 if (data_duplicate) { 413 struct action *a; 414 uint32_t i; 415 416 /* action_id. */ 417 for (i = 0; i < table->info.n_actions; i++) 418 if (entry->action_id == table->actions[i].action_id) 419 break; 420 421 if (i >= table->info.n_actions) 422 goto error; 423 424 new_entry->action_id = entry->action_id; 425 426 /* action_data. */ 427 a = &ctl->actions[entry->action_id]; 428 if (a->data_size && !entry->action_data) 429 goto error; 430 431 /* The table layer provisions a constant action data size per 432 * entry, which should be the largest data size for all the 433 * actions enabled for the current table, and attempts to copy 434 * this many bytes each time a table entry is added, even if the 435 * specific action requires less data or even no data at all, 436 * hence we always have to allocate the max. 437 */ 438 new_entry->action_data = calloc(1, table->params.action_data_size); 439 if (!new_entry->action_data) 440 goto error; 441 442 if (a->data_size) 443 memcpy(new_entry->action_data, 444 entry->action_data, 445 a->data_size); 446 } 447 448 return new_entry; 449 450 error: 451 table_entry_free(new_entry); 452 return NULL; 453 } 454 455 static int 456 table_entry_keycmp(struct table *table, 457 struct rte_swx_table_entry *e0, 458 struct rte_swx_table_entry *e1) 459 { 460 uint32_t key_size = table->params.key_size; 461 uint32_t i; 462 463 for (i = 0; i < key_size; i++) { 464 uint8_t *key_mask0 = table->params.key_mask0; 465 uint8_t km0, km[2], k[2]; 466 467 km0 = key_mask0 ? key_mask0[i] : 0xFF; 468 469 km[0] = e0->key_mask ? e0->key_mask[i] : 0xFF; 470 km[1] = e1->key_mask ? e1->key_mask[i] : 0xFF; 471 472 k[0] = e0->key[i]; 473 k[1] = e1->key[i]; 474 475 /* Mask comparison. */ 476 if ((km[0] & km0) != (km[1] & km0)) 477 return 1; /* Not equal. */ 478 479 /* Value comparison. */ 480 if ((k[0] & km[0] & km0) != (k[1] & km[1] & km0)) 481 return 1; /* Not equal. */ 482 } 483 484 return 0; /* Equal. */ 485 } 486 487 static struct rte_swx_table_entry * 488 table_entries_find(struct table *table, struct rte_swx_table_entry *entry) 489 { 490 struct rte_swx_table_entry *e; 491 492 TAILQ_FOREACH(e, &table->entries, node) 493 if (!table_entry_keycmp(table, entry, e)) 494 return e; /* Found. */ 495 496 return NULL; /* Not found. */ 497 } 498 499 static void 500 table_entries_free(struct table *table) 501 { 502 for ( ; ; ) { 503 struct rte_swx_table_entry *entry; 504 505 entry = TAILQ_FIRST(&table->entries); 506 if (!entry) 507 break; 508 509 TAILQ_REMOVE(&table->entries, entry, node); 510 table_entry_free(entry); 511 } 512 } 513 514 static struct rte_swx_table_entry * 515 table_pending_add_find(struct table *table, struct rte_swx_table_entry *entry) 516 { 517 struct rte_swx_table_entry *e; 518 519 TAILQ_FOREACH(e, &table->pending_add, node) 520 if (!table_entry_keycmp(table, entry, e)) 521 return e; /* Found. */ 522 523 return NULL; /* Not found. */ 524 } 525 526 static void 527 table_pending_add_admit(struct table *table) 528 { 529 TAILQ_CONCAT(&table->entries, &table->pending_add, node); 530 } 531 532 static void 533 table_pending_add_free(struct table *table) 534 { 535 for ( ; ; ) { 536 struct rte_swx_table_entry *entry; 537 538 entry = TAILQ_FIRST(&table->pending_add); 539 if (!entry) 540 break; 541 542 TAILQ_REMOVE(&table->pending_add, entry, node); 543 table_entry_free(entry); 544 } 545 } 546 547 static struct rte_swx_table_entry * 548 table_pending_modify0_find(struct table *table, 549 struct rte_swx_table_entry *entry) 550 { 551 struct rte_swx_table_entry *e; 552 553 TAILQ_FOREACH(e, &table->pending_modify0, node) 554 if (!table_entry_keycmp(table, entry, e)) 555 return e; /* Found. */ 556 557 return NULL; /* Not found. */ 558 } 559 560 static void 561 table_pending_modify0_admit(struct table *table) 562 { 563 TAILQ_CONCAT(&table->entries, &table->pending_modify0, node); 564 } 565 566 static void 567 table_pending_modify0_free(struct table *table) 568 { 569 for ( ; ; ) { 570 struct rte_swx_table_entry *entry; 571 572 entry = TAILQ_FIRST(&table->pending_modify0); 573 if (!entry) 574 break; 575 576 TAILQ_REMOVE(&table->pending_modify0, entry, node); 577 table_entry_free(entry); 578 } 579 } 580 581 static struct rte_swx_table_entry * 582 table_pending_modify1_find(struct table *table, 583 struct rte_swx_table_entry *entry) 584 { 585 struct rte_swx_table_entry *e; 586 587 TAILQ_FOREACH(e, &table->pending_modify1, node) 588 if (!table_entry_keycmp(table, entry, e)) 589 return e; /* Found. */ 590 591 return NULL; /* Not found. */ 592 } 593 594 static void 595 table_pending_modify1_admit(struct table *table) 596 { 597 TAILQ_CONCAT(&table->entries, &table->pending_modify1, node); 598 } 599 600 static void 601 table_pending_modify1_free(struct table *table) 602 { 603 for ( ; ; ) { 604 struct rte_swx_table_entry *entry; 605 606 entry = TAILQ_FIRST(&table->pending_modify1); 607 if (!entry) 608 break; 609 610 TAILQ_REMOVE(&table->pending_modify1, entry, node); 611 table_entry_free(entry); 612 } 613 } 614 615 static struct rte_swx_table_entry * 616 table_pending_delete_find(struct table *table, 617 struct rte_swx_table_entry *entry) 618 { 619 struct rte_swx_table_entry *e; 620 621 TAILQ_FOREACH(e, &table->pending_delete, node) 622 if (!table_entry_keycmp(table, entry, e)) 623 return e; /* Found. */ 624 625 return NULL; /* Not found. */ 626 } 627 628 static void 629 table_pending_delete_admit(struct table *table) 630 { 631 TAILQ_CONCAT(&table->entries, &table->pending_delete, node); 632 } 633 634 static void 635 table_pending_delete_free(struct table *table) 636 { 637 for ( ; ; ) { 638 struct rte_swx_table_entry *entry; 639 640 entry = TAILQ_FIRST(&table->pending_delete); 641 if (!entry) 642 break; 643 644 TAILQ_REMOVE(&table->pending_delete, entry, node); 645 table_entry_free(entry); 646 } 647 } 648 649 static void 650 table_pending_default_free(struct table *table) 651 { 652 if (!table->pending_default) 653 return; 654 655 free(table->pending_default->action_data); 656 free(table->pending_default); 657 table->pending_default = NULL; 658 } 659 660 static int 661 table_is_update_pending(struct table *table, int consider_pending_default) 662 { 663 struct rte_swx_table_entry *e; 664 uint32_t n = 0; 665 666 /* Pending add. */ 667 TAILQ_FOREACH(e, &table->pending_add, node) 668 n++; 669 670 /* Pending modify. */ 671 TAILQ_FOREACH(e, &table->pending_modify1, node) 672 n++; 673 674 /* Pending delete. */ 675 TAILQ_FOREACH(e, &table->pending_delete, node) 676 n++; 677 678 /* Pending default. */ 679 if (consider_pending_default && table->pending_default) 680 n++; 681 682 return n; 683 } 684 685 static void 686 table_free(struct rte_swx_ctl_pipeline *ctl) 687 { 688 uint32_t i; 689 690 if (!ctl->tables) 691 return; 692 693 for (i = 0; i < ctl->info.n_tables; i++) { 694 struct table *table = &ctl->tables[i]; 695 696 free(table->mf); 697 free(table->actions); 698 free(table->params.key_mask0); 699 700 table_entries_free(table); 701 table_pending_add_free(table); 702 table_pending_modify0_free(table); 703 table_pending_modify1_free(table); 704 table_pending_delete_free(table); 705 table_pending_default_free(table); 706 } 707 708 free(ctl->tables); 709 ctl->tables = NULL; 710 } 711 712 static void 713 table_state_free(struct rte_swx_ctl_pipeline *ctl) 714 { 715 uint32_t i; 716 717 if (!ctl->ts_next) 718 return; 719 720 /* For each table, free its table state. */ 721 for (i = 0; i < ctl->info.n_tables; i++) { 722 struct table *table = &ctl->tables[i]; 723 struct rte_swx_table_state *ts = &ctl->ts_next[i]; 724 725 /* Default action data. */ 726 free(ts->default_action_data); 727 728 /* Table object. */ 729 if (!table->is_stub && table->ops.free && ts->obj) 730 table->ops.free(ts->obj); 731 } 732 733 free(ctl->ts_next); 734 ctl->ts_next = NULL; 735 } 736 737 static int 738 table_state_create(struct rte_swx_ctl_pipeline *ctl) 739 { 740 int status = 0; 741 uint32_t i; 742 743 ctl->ts_next = calloc(ctl->info.n_tables, 744 sizeof(struct rte_swx_table_state)); 745 if (!ctl->ts_next) { 746 status = -ENOMEM; 747 goto error; 748 } 749 750 for (i = 0; i < ctl->info.n_tables; i++) { 751 struct table *table = &ctl->tables[i]; 752 struct rte_swx_table_state *ts = &ctl->ts[i]; 753 struct rte_swx_table_state *ts_next = &ctl->ts_next[i]; 754 755 /* Table object. */ 756 if (!table->is_stub && table->ops.add) { 757 ts_next->obj = table->ops.create(&table->params, 758 &table->entries, 759 table->info.args, 760 ctl->numa_node); 761 if (!ts_next->obj) { 762 status = -ENODEV; 763 goto error; 764 } 765 } 766 767 if (!table->is_stub && !table->ops.add) 768 ts_next->obj = ts->obj; 769 770 /* Default action data: duplicate from current table state. */ 771 ts_next->default_action_data = 772 malloc(table->params.action_data_size); 773 if (!ts_next->default_action_data) { 774 status = -ENOMEM; 775 goto error; 776 } 777 778 memcpy(ts_next->default_action_data, 779 ts->default_action_data, 780 table->params.action_data_size); 781 782 ts_next->default_action_id = ts->default_action_id; 783 } 784 785 return 0; 786 787 error: 788 table_state_free(ctl); 789 return status; 790 } 791 792 void 793 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl) 794 { 795 if (!ctl) 796 return; 797 798 action_free(ctl); 799 800 table_state_free(ctl); 801 802 table_free(ctl); 803 804 free(ctl); 805 } 806 807 struct rte_swx_ctl_pipeline * 808 rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p) 809 { 810 struct rte_swx_ctl_pipeline *ctl = NULL; 811 uint32_t i; 812 int status; 813 814 if (!p) 815 goto error; 816 817 ctl = calloc(1, sizeof(struct rte_swx_ctl_pipeline)); 818 if (!ctl) 819 goto error; 820 821 /* info. */ 822 status = rte_swx_ctl_pipeline_info_get(p, &ctl->info); 823 if (status) 824 goto error; 825 826 /* numa_node. */ 827 status = rte_swx_ctl_pipeline_numa_node_get(p, &ctl->numa_node); 828 if (status) 829 goto error; 830 831 /* p. */ 832 ctl->p = p; 833 834 /* actions. */ 835 ctl->actions = calloc(ctl->info.n_actions, sizeof(struct action)); 836 if (!ctl->actions) 837 goto error; 838 839 for (i = 0; i < ctl->info.n_actions; i++) { 840 struct action *a = &ctl->actions[i]; 841 uint32_t j; 842 843 /* info. */ 844 status = rte_swx_ctl_action_info_get(p, i, &a->info); 845 if (status) 846 goto error; 847 848 /* args. */ 849 a->args = calloc(a->info.n_args, 850 sizeof(struct rte_swx_ctl_action_arg_info)); 851 if (!a->args) 852 goto error; 853 854 for (j = 0; j < a->info.n_args; j++) { 855 status = rte_swx_ctl_action_arg_info_get(p, 856 i, 857 j, 858 &a->args[j]); 859 if (status) 860 goto error; 861 } 862 863 /* data_size. */ 864 for (j = 0; j < a->info.n_args; j++) { 865 struct rte_swx_ctl_action_arg_info *info = &a->args[j]; 866 867 a->data_size += info->n_bits; 868 } 869 870 a->data_size = (a->data_size + 7) / 8; 871 } 872 873 /* tables. */ 874 ctl->tables = calloc(ctl->info.n_tables, sizeof(struct table)); 875 if (!ctl->tables) 876 goto error; 877 878 for (i = 0; i < ctl->info.n_tables; i++) { 879 struct table *t = &ctl->tables[i]; 880 881 TAILQ_INIT(&t->entries); 882 TAILQ_INIT(&t->pending_add); 883 TAILQ_INIT(&t->pending_modify0); 884 TAILQ_INIT(&t->pending_modify1); 885 TAILQ_INIT(&t->pending_delete); 886 } 887 888 for (i = 0; i < ctl->info.n_tables; i++) { 889 struct table *t = &ctl->tables[i]; 890 uint32_t j; 891 892 /* info. */ 893 status = rte_swx_ctl_table_info_get(p, i, &t->info); 894 if (status) 895 goto error; 896 897 /* mf. */ 898 t->mf = calloc(t->info.n_match_fields, 899 sizeof(struct rte_swx_ctl_table_match_field_info)); 900 if (!t->mf) 901 goto error; 902 903 for (j = 0; j < t->info.n_match_fields; j++) { 904 status = rte_swx_ctl_table_match_field_info_get(p, 905 i, 906 j, 907 &t->mf[j]); 908 if (status) 909 goto error; 910 } 911 912 /* actions. */ 913 t->actions = calloc(t->info.n_actions, 914 sizeof(struct rte_swx_ctl_table_action_info)); 915 if (!t->actions) 916 goto error; 917 918 for (j = 0; j < t->info.n_actions; j++) { 919 status = rte_swx_ctl_table_action_info_get(p, 920 i, 921 j, 922 &t->actions[j]); 923 if (status || 924 t->actions[j].action_id >= ctl->info.n_actions) 925 goto error; 926 } 927 928 /* ops, is_stub. */ 929 status = rte_swx_ctl_table_ops_get(p, i, &t->ops, &t->is_stub); 930 if (status) 931 goto error; 932 933 if ((t->is_stub && t->info.n_match_fields) || 934 (!t->is_stub && !t->info.n_match_fields)) 935 goto error; 936 937 /* params. */ 938 status = table_params_get(ctl, i); 939 if (status) 940 goto error; 941 } 942 943 /* ts. */ 944 status = rte_swx_pipeline_table_state_get(p, &ctl->ts); 945 if (status) 946 goto error; 947 948 /* ts_next. */ 949 status = table_state_create(ctl); 950 if (status) 951 goto error; 952 953 return ctl; 954 955 error: 956 rte_swx_ctl_pipeline_free(ctl); 957 return NULL; 958 } 959 960 int 961 rte_swx_ctl_pipeline_table_entry_add(struct rte_swx_ctl_pipeline *ctl, 962 const char *table_name, 963 struct rte_swx_table_entry *entry) 964 { 965 struct table *table; 966 struct rte_swx_table_entry *new_entry, *existing_entry; 967 uint32_t table_id; 968 969 CHECK(ctl, EINVAL); 970 CHECK(table_name && table_name[0], EINVAL); 971 972 table = table_find(ctl, table_name); 973 CHECK(table, EINVAL); 974 table_id = table - ctl->tables; 975 976 CHECK(entry, EINVAL); 977 CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL); 978 979 new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1); 980 CHECK(new_entry, ENOMEM); 981 982 /* The new entry is found in the table->entries list: 983 * - Add the new entry to the table->pending_modify1 list; 984 * - Move the existing entry from the table->entries list to the 985 * table->pending_modify0 list. 986 */ 987 existing_entry = table_entries_find(table, entry); 988 if (existing_entry) { 989 TAILQ_INSERT_TAIL(&table->pending_modify1, 990 new_entry, 991 node); 992 993 TAILQ_REMOVE(&table->entries, 994 existing_entry, 995 node); 996 997 TAILQ_INSERT_TAIL(&table->pending_modify0, 998 existing_entry, 999 node); 1000 1001 return 0; 1002 } 1003 1004 /* The new entry is found in the table->pending_add list: 1005 * - Replace the entry in the table->pending_add list with the new entry 1006 * (and free the replaced entry). 1007 */ 1008 existing_entry = table_pending_add_find(table, entry); 1009 if (existing_entry) { 1010 TAILQ_INSERT_AFTER(&table->pending_add, 1011 existing_entry, 1012 new_entry, 1013 node); 1014 1015 TAILQ_REMOVE(&table->pending_add, 1016 existing_entry, 1017 node); 1018 1019 table_entry_free(existing_entry); 1020 1021 return 0; 1022 } 1023 1024 /* The new entry is found in the table->pending_modify1 list: 1025 * - Replace the entry in the table->pending_modify1 list with the new 1026 * entry (and free the replaced entry). 1027 */ 1028 existing_entry = table_pending_modify1_find(table, entry); 1029 if (existing_entry) { 1030 TAILQ_INSERT_AFTER(&table->pending_modify1, 1031 existing_entry, 1032 new_entry, 1033 node); 1034 1035 TAILQ_REMOVE(&table->pending_modify1, 1036 existing_entry, 1037 node); 1038 1039 table_entry_free(existing_entry); 1040 1041 return 0; 1042 } 1043 1044 /* The new entry is found in the table->pending_delete list: 1045 * - Add the new entry to the table->pending_modify1 list; 1046 * - Move the existing entry from the table->pending_delete list to the 1047 * table->pending_modify0 list. 1048 */ 1049 existing_entry = table_pending_delete_find(table, entry); 1050 if (existing_entry) { 1051 TAILQ_INSERT_TAIL(&table->pending_modify1, 1052 new_entry, 1053 node); 1054 1055 TAILQ_REMOVE(&table->pending_delete, 1056 existing_entry, 1057 node); 1058 1059 TAILQ_INSERT_TAIL(&table->pending_modify0, 1060 existing_entry, 1061 node); 1062 1063 return 0; 1064 } 1065 1066 /* The new entry is not found in any of the above lists: 1067 * - Add the new entry to the table->pending_add list. 1068 */ 1069 TAILQ_INSERT_TAIL(&table->pending_add, new_entry, node); 1070 1071 return 0; 1072 } 1073 1074 int 1075 rte_swx_ctl_pipeline_table_entry_delete(struct rte_swx_ctl_pipeline *ctl, 1076 const char *table_name, 1077 struct rte_swx_table_entry *entry) 1078 { 1079 struct table *table; 1080 struct rte_swx_table_entry *existing_entry; 1081 uint32_t table_id; 1082 1083 CHECK(ctl, EINVAL); 1084 1085 CHECK(table_name && table_name[0], EINVAL); 1086 table = table_find(ctl, table_name); 1087 CHECK(table, EINVAL); 1088 table_id = table - ctl->tables; 1089 1090 CHECK(entry, EINVAL); 1091 CHECK(!table_entry_check(ctl, table_id, entry, 1, 0), EINVAL); 1092 1093 /* The entry is found in the table->entries list: 1094 * - Move the existing entry from the table->entries list to to the 1095 * table->pending_delete list. 1096 */ 1097 existing_entry = table_entries_find(table, entry); 1098 if (existing_entry) { 1099 TAILQ_REMOVE(&table->entries, 1100 existing_entry, 1101 node); 1102 1103 TAILQ_INSERT_TAIL(&table->pending_delete, 1104 existing_entry, 1105 node); 1106 1107 return 0; 1108 } 1109 1110 /* The entry is found in the table->pending_add list: 1111 * - Remove the entry from the table->pending_add list and free it. 1112 */ 1113 existing_entry = table_pending_add_find(table, entry); 1114 if (existing_entry) { 1115 TAILQ_REMOVE(&table->pending_add, 1116 existing_entry, 1117 node); 1118 1119 table_entry_free(existing_entry); 1120 } 1121 1122 /* The entry is found in the table->pending_modify1 list: 1123 * - Free the entry in the table->pending_modify1 list; 1124 * - Move the existing entry from the table->pending_modify0 list to the 1125 * table->pending_delete list. 1126 */ 1127 existing_entry = table_pending_modify1_find(table, entry); 1128 if (existing_entry) { 1129 struct rte_swx_table_entry *real_existing_entry; 1130 1131 TAILQ_REMOVE(&table->pending_modify1, 1132 existing_entry, 1133 node); 1134 1135 table_entry_free(existing_entry); 1136 1137 real_existing_entry = table_pending_modify0_find(table, entry); 1138 CHECK(real_existing_entry, EINVAL); /* Coverity. */ 1139 1140 TAILQ_REMOVE(&table->pending_modify0, 1141 real_existing_entry, 1142 node); 1143 1144 TAILQ_INSERT_TAIL(&table->pending_delete, 1145 real_existing_entry, 1146 node); 1147 1148 return 0; 1149 } 1150 1151 /* The entry is found in the table->pending_delete list: 1152 * - Do nothing: the existing entry is already in the 1153 * table->pending_delete list, i.e. already marked for delete, so 1154 * simply keep it there as it is. 1155 */ 1156 1157 /* The entry is not found in any of the above lists: 1158 * - Do nothing: no existing entry to delete. 1159 */ 1160 1161 return 0; 1162 } 1163 1164 int 1165 rte_swx_ctl_pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *ctl, 1166 const char *table_name, 1167 struct rte_swx_table_entry *entry) 1168 { 1169 struct table *table; 1170 struct rte_swx_table_entry *new_entry; 1171 uint32_t table_id; 1172 1173 CHECK(ctl, EINVAL); 1174 1175 CHECK(table_name && table_name[0], EINVAL); 1176 table = table_find(ctl, table_name); 1177 CHECK(table, EINVAL); 1178 table_id = table - ctl->tables; 1179 CHECK(!table->info.default_action_is_const, EINVAL); 1180 1181 CHECK(entry, EINVAL); 1182 CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL); 1183 1184 new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1); 1185 CHECK(new_entry, ENOMEM); 1186 1187 table_pending_default_free(table); 1188 1189 table->pending_default = new_entry; 1190 return 0; 1191 } 1192 1193 1194 static void 1195 table_entry_list_free(struct rte_swx_table_entry_list *list) 1196 { 1197 for ( ; ; ) { 1198 struct rte_swx_table_entry *entry; 1199 1200 entry = TAILQ_FIRST(list); 1201 if (!entry) 1202 break; 1203 1204 TAILQ_REMOVE(list, entry, node); 1205 table_entry_free(entry); 1206 } 1207 } 1208 1209 static int 1210 table_entry_list_duplicate(struct rte_swx_ctl_pipeline *ctl, 1211 uint32_t table_id, 1212 struct rte_swx_table_entry_list *dst, 1213 struct rte_swx_table_entry_list *src) 1214 { 1215 struct rte_swx_table_entry *src_entry; 1216 1217 TAILQ_FOREACH(src_entry, src, node) { 1218 struct rte_swx_table_entry *dst_entry; 1219 1220 dst_entry = table_entry_duplicate(ctl, table_id, src_entry, 1, 1); 1221 if (!dst_entry) 1222 goto error; 1223 1224 TAILQ_INSERT_TAIL(dst, dst_entry, node); 1225 } 1226 1227 return 0; 1228 1229 error: 1230 table_entry_list_free(dst); 1231 return -ENOMEM; 1232 } 1233 1234 /* This commit stage contains all the operations that can fail; in case ANY of 1235 * them fails for ANY table, ALL of them are rolled back for ALL the tables. 1236 */ 1237 static int 1238 table_rollfwd0(struct rte_swx_ctl_pipeline *ctl, 1239 uint32_t table_id, 1240 uint32_t after_swap) 1241 { 1242 struct table *table = &ctl->tables[table_id]; 1243 struct rte_swx_table_state *ts = &ctl->ts[table_id]; 1244 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id]; 1245 1246 if (table->is_stub || !table_is_update_pending(table, 0)) 1247 return 0; 1248 1249 /* 1250 * Current table supports incremental update. 1251 */ 1252 if (table->ops.add) { 1253 /* Reset counters. */ 1254 table->n_add = 0; 1255 table->n_modify = 0; 1256 table->n_delete = 0; 1257 1258 /* Add pending rules. */ 1259 struct rte_swx_table_entry *entry; 1260 1261 TAILQ_FOREACH(entry, &table->pending_add, node) { 1262 int status; 1263 1264 status = table->ops.add(ts_next->obj, entry); 1265 if (status) 1266 return status; 1267 1268 table->n_add++; 1269 } 1270 1271 /* Modify pending rules. */ 1272 TAILQ_FOREACH(entry, &table->pending_modify1, node) { 1273 int status; 1274 1275 status = table->ops.add(ts_next->obj, entry); 1276 if (status) 1277 return status; 1278 1279 table->n_modify++; 1280 } 1281 1282 /* Delete pending rules. */ 1283 TAILQ_FOREACH(entry, &table->pending_delete, node) { 1284 int status; 1285 1286 status = table->ops.del(ts_next->obj, entry); 1287 if (status) 1288 return status; 1289 1290 table->n_delete++; 1291 } 1292 1293 return 0; 1294 } 1295 1296 /* 1297 * Current table does NOT support incremental update. 1298 */ 1299 if (!after_swap) { 1300 struct rte_swx_table_entry_list list; 1301 int status; 1302 1303 /* Create updated list of entries included. */ 1304 TAILQ_INIT(&list); 1305 1306 status = table_entry_list_duplicate(ctl, 1307 table_id, 1308 &list, 1309 &table->entries); 1310 if (status) 1311 goto error; 1312 1313 status = table_entry_list_duplicate(ctl, 1314 table_id, 1315 &list, 1316 &table->pending_add); 1317 if (status) 1318 goto error; 1319 1320 status = table_entry_list_duplicate(ctl, 1321 table_id, 1322 &list, 1323 &table->pending_modify1); 1324 if (status) 1325 goto error; 1326 1327 /* Create new table object with the updates included. */ 1328 ts_next->obj = table->ops.create(&table->params, 1329 &list, 1330 table->info.args, 1331 ctl->numa_node); 1332 if (!ts_next->obj) { 1333 status = -ENODEV; 1334 goto error; 1335 } 1336 1337 table_entry_list_free(&list); 1338 1339 return 0; 1340 1341 error: 1342 table_entry_list_free(&list); 1343 return status; 1344 } 1345 1346 /* Free the old table object. */ 1347 if (ts_next->obj && table->ops.free) 1348 table->ops.free(ts_next->obj); 1349 1350 /* Copy over the new table object. */ 1351 ts_next->obj = ts->obj; 1352 1353 return 0; 1354 } 1355 1356 /* This commit stage contains all the operations that cannot fail. They are 1357 * executed only if the previous stage was successful for ALL the tables. Hence, 1358 * none of these operations has to be rolled back for ANY table. 1359 */ 1360 static void 1361 table_rollfwd1(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 1362 { 1363 struct table *table = &ctl->tables[table_id]; 1364 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id]; 1365 struct action *a; 1366 uint8_t *action_data; 1367 uint64_t action_id; 1368 1369 /* Copy the pending default entry. */ 1370 if (!table->pending_default) 1371 return; 1372 1373 action_id = table->pending_default->action_id; 1374 action_data = table->pending_default->action_data; 1375 a = &ctl->actions[action_id]; 1376 1377 memcpy(ts_next->default_action_data, 1378 action_data, 1379 a->data_size); 1380 1381 ts_next->default_action_id = action_id; 1382 } 1383 1384 /* This last commit stage is simply finalizing a successful commit operation. 1385 * This stage is only executed if all the previous stages were successful. This 1386 * stage cannot fail. 1387 */ 1388 static void 1389 table_rollfwd2(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 1390 { 1391 struct table *table = &ctl->tables[table_id]; 1392 1393 /* Move all the pending add entries to the table, as they are now part 1394 * of the table. 1395 */ 1396 table_pending_add_admit(table); 1397 1398 /* Move all the pending modify1 entries to table, are they are now part 1399 * of the table. Free up all the pending modify0 entries, as they are no 1400 * longer part of the table. 1401 */ 1402 table_pending_modify1_admit(table); 1403 table_pending_modify0_free(table); 1404 1405 /* Free up all the pending delete entries, as they are no longer part of 1406 * the table. 1407 */ 1408 table_pending_delete_free(table); 1409 1410 /* Free up the pending default entry, as it is now part of the table. */ 1411 table_pending_default_free(table); 1412 } 1413 1414 /* The rollback stage is only executed when the commit failed, i.e. ANY of the 1415 * commit operations that can fail did fail for ANY table. It reverts ALL the 1416 * tables to their state before the commit started, as if the commit never 1417 * happened. 1418 */ 1419 static void 1420 table_rollback(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 1421 { 1422 struct table *table = &ctl->tables[table_id]; 1423 struct rte_swx_table_state *ts_next = &ctl->ts_next[table_id]; 1424 1425 if (table->is_stub || !table_is_update_pending(table, 0)) 1426 return; 1427 1428 if (table->ops.add) { 1429 struct rte_swx_table_entry *entry; 1430 1431 /* Add back all the entries that were just deleted. */ 1432 TAILQ_FOREACH(entry, &table->pending_delete, node) { 1433 if (!table->n_delete) 1434 break; 1435 1436 table->ops.add(ts_next->obj, entry); 1437 table->n_delete--; 1438 } 1439 1440 /* Add back the old copy for all the entries that were just 1441 * modified. 1442 */ 1443 TAILQ_FOREACH(entry, &table->pending_modify0, node) { 1444 if (!table->n_modify) 1445 break; 1446 1447 table->ops.add(ts_next->obj, entry); 1448 table->n_modify--; 1449 } 1450 1451 /* Delete all the entries that were just added. */ 1452 TAILQ_FOREACH(entry, &table->pending_add, node) { 1453 if (!table->n_add) 1454 break; 1455 1456 table->ops.del(ts_next->obj, entry); 1457 table->n_add--; 1458 } 1459 } else { 1460 struct rte_swx_table_state *ts = &ctl->ts[table_id]; 1461 1462 /* Free the new table object, as update was cancelled. */ 1463 if (ts_next->obj && table->ops.free) 1464 table->ops.free(ts_next->obj); 1465 1466 /* Reinstate the old table object. */ 1467 ts_next->obj = ts->obj; 1468 } 1469 } 1470 1471 /* This stage is conditionally executed (as instructed by the user) after a 1472 * failed commit operation to remove ALL the pending work for ALL the tables. 1473 */ 1474 static void 1475 table_abort(struct rte_swx_ctl_pipeline *ctl, uint32_t table_id) 1476 { 1477 struct table *table = &ctl->tables[table_id]; 1478 1479 /* Free up all the pending add entries, as none of them is part of the 1480 * table. 1481 */ 1482 table_pending_add_free(table); 1483 1484 /* Free up all the pending modify1 entries, as none of them made it to 1485 * the table. Add back all the pending modify0 entries, as none of them 1486 * was deleted from the table. 1487 */ 1488 table_pending_modify1_free(table); 1489 table_pending_modify0_admit(table); 1490 1491 /* Add back all the pending delete entries, as none of them was deleted 1492 * from the table. 1493 */ 1494 table_pending_delete_admit(table); 1495 1496 /* Free up the pending default entry, as it is no longer going to be 1497 * added to the table. 1498 */ 1499 table_pending_default_free(table); 1500 } 1501 1502 int 1503 rte_swx_ctl_pipeline_commit(struct rte_swx_ctl_pipeline *ctl, int abort_on_fail) 1504 { 1505 struct rte_swx_table_state *ts; 1506 int status = 0; 1507 uint32_t i; 1508 1509 CHECK(ctl, EINVAL); 1510 1511 /* Operate the changes on the current ts_next before it becomes the new 1512 * ts. 1513 */ 1514 for (i = 0; i < ctl->info.n_tables; i++) { 1515 status = table_rollfwd0(ctl, i, 0); 1516 if (status) 1517 goto rollback; 1518 } 1519 1520 for (i = 0; i < ctl->info.n_tables; i++) 1521 table_rollfwd1(ctl, i); 1522 1523 /* Swap the table state for the data plane. The current ts and ts_next 1524 * become the new ts_next and ts, respectively. 1525 */ 1526 rte_swx_pipeline_table_state_set(ctl->p, ctl->ts_next); 1527 usleep(100); 1528 ts = ctl->ts; 1529 ctl->ts = ctl->ts_next; 1530 ctl->ts_next = ts; 1531 1532 /* Operate the changes on the current ts_next, which is the previous ts. 1533 */ 1534 for (i = 0; i < ctl->info.n_tables; i++) { 1535 table_rollfwd0(ctl, i, 1); 1536 table_rollfwd1(ctl, i); 1537 table_rollfwd2(ctl, i); 1538 } 1539 1540 return 0; 1541 1542 rollback: 1543 for (i = 0; i < ctl->info.n_tables; i++) { 1544 table_rollback(ctl, i); 1545 if (abort_on_fail) 1546 table_abort(ctl, i); 1547 } 1548 1549 return status; 1550 } 1551 1552 void 1553 rte_swx_ctl_pipeline_abort(struct rte_swx_ctl_pipeline *ctl) 1554 { 1555 uint32_t i; 1556 1557 if (!ctl) 1558 return; 1559 1560 for (i = 0; i < ctl->info.n_tables; i++) 1561 table_abort(ctl, i); 1562 } 1563 1564 static int 1565 token_is_comment(const char *token) 1566 { 1567 if ((token[0] == '#') || 1568 (token[0] == ';') || 1569 ((token[0] == '/') && (token[1] == '/'))) 1570 return 1; /* TRUE. */ 1571 1572 return 0; /* FALSE. */ 1573 } 1574 1575 #define RTE_SWX_CTL_ENTRY_TOKENS_MAX 256 1576 1577 struct rte_swx_table_entry * 1578 rte_swx_ctl_pipeline_table_entry_read(struct rte_swx_ctl_pipeline *ctl, 1579 const char *table_name, 1580 const char *string, 1581 int *is_blank_or_comment) 1582 { 1583 char *token_array[RTE_SWX_CTL_ENTRY_TOKENS_MAX], **tokens; 1584 struct table *table; 1585 struct action *action; 1586 struct rte_swx_table_entry *entry = NULL; 1587 char *s0 = NULL, *s; 1588 uint32_t n_tokens = 0, arg_offset = 0, i; 1589 int blank_or_comment = 0; 1590 1591 /* Check input arguments. */ 1592 if (!ctl) 1593 goto error; 1594 1595 if (!table_name || !table_name[0]) 1596 goto error; 1597 1598 table = table_find(ctl, table_name); 1599 if (!table) 1600 goto error; 1601 1602 if (!string || !string[0]) 1603 goto error; 1604 1605 /* Memory allocation. */ 1606 s0 = strdup(string); 1607 if (!s0) 1608 goto error; 1609 1610 entry = table_entry_alloc(table); 1611 if (!entry) 1612 goto error; 1613 1614 /* Parse the string into tokens. */ 1615 for (s = s0; ; ) { 1616 char *token; 1617 1618 token = strtok_r(s, " \f\n\r\t\v", &s); 1619 if (!token || token_is_comment(token)) 1620 break; 1621 1622 if (n_tokens >= RTE_SWX_CTL_ENTRY_TOKENS_MAX) 1623 goto error; 1624 1625 token_array[n_tokens] = token; 1626 n_tokens++; 1627 } 1628 1629 if (!n_tokens) { 1630 blank_or_comment = 1; 1631 goto error; 1632 } 1633 1634 tokens = token_array; 1635 1636 /* 1637 * Match. 1638 */ 1639 if (n_tokens && strcmp(tokens[0], "match")) 1640 goto action; 1641 1642 if (n_tokens < 1 + table->info.n_match_fields) 1643 goto error; 1644 1645 for (i = 0; i < table->info.n_match_fields; i++) { 1646 struct rte_swx_ctl_table_match_field_info *mf = &table->mf[i]; 1647 char *mf_val = tokens[1 + i], *mf_mask = NULL; 1648 uint64_t val, mask = UINT64_MAX; 1649 uint32_t offset = (mf->offset - table->mf_first->offset) / 8; 1650 1651 /* 1652 * Mask. 1653 */ 1654 mf_mask = strchr(mf_val, '/'); 1655 if (mf_mask) { 1656 *mf_mask = 0; 1657 mf_mask++; 1658 1659 /* Parse. */ 1660 mask = strtoull(mf_mask, &mf_mask, 0); 1661 if (mf_mask[0]) 1662 goto error; 1663 1664 /* Endianness conversion. */ 1665 if (mf->is_header) 1666 mask = field_hton(mask, mf->n_bits); 1667 } 1668 1669 /* Copy to entry. */ 1670 if (entry->key_mask) 1671 memcpy(&entry->key_mask[offset], 1672 (uint8_t *)&mask, 1673 mf->n_bits / 8); 1674 1675 /* 1676 * Value. 1677 */ 1678 /* Parse. */ 1679 val = strtoull(mf_val, &mf_val, 0); 1680 if (mf_val[0]) 1681 goto error; 1682 1683 /* Endianness conversion. */ 1684 if (mf->is_header) 1685 val = field_hton(val, mf->n_bits); 1686 1687 /* Copy to entry. */ 1688 memcpy(&entry->key[offset], 1689 (uint8_t *)&val, 1690 mf->n_bits / 8); 1691 } 1692 1693 tokens += 1 + table->info.n_match_fields; 1694 n_tokens -= 1 + table->info.n_match_fields; 1695 1696 /* 1697 * Match priority. 1698 */ 1699 if (n_tokens && !strcmp(tokens[0], "priority")) { 1700 char *priority = tokens[1]; 1701 uint32_t val; 1702 1703 if (n_tokens < 2) 1704 goto error; 1705 1706 /* Parse. */ 1707 val = strtoul(priority, &priority, 0); 1708 if (priority[0]) 1709 goto error; 1710 1711 /* Copy to entry. */ 1712 entry->key_priority = val; 1713 1714 tokens += 2; 1715 n_tokens -= 2; 1716 } 1717 1718 /* 1719 * Action. 1720 */ 1721 action: 1722 if (n_tokens && strcmp(tokens[0], "action")) 1723 goto other; 1724 1725 if (n_tokens < 2) 1726 goto error; 1727 1728 action = action_find(ctl, tokens[1]); 1729 if (!action) 1730 goto error; 1731 1732 if (n_tokens < 2 + action->info.n_args * 2) 1733 goto error; 1734 1735 /* action_id. */ 1736 entry->action_id = action - ctl->actions; 1737 1738 /* action_data. */ 1739 for (i = 0; i < action->info.n_args; i++) { 1740 struct rte_swx_ctl_action_arg_info *arg = &action->args[i]; 1741 char *arg_name, *arg_val; 1742 uint64_t val; 1743 1744 arg_name = tokens[2 + i * 2]; 1745 arg_val = tokens[2 + i * 2 + 1]; 1746 1747 if (strcmp(arg_name, arg->name)) 1748 goto error; 1749 1750 val = strtoull(arg_val, &arg_val, 0); 1751 if (arg_val[0]) 1752 goto error; 1753 1754 /* Endianness conversion. */ 1755 if (arg->is_network_byte_order) 1756 val = field_hton(val, arg->n_bits); 1757 1758 /* Copy to entry. */ 1759 memcpy(&entry->action_data[arg_offset], 1760 (uint8_t *)&val, 1761 arg->n_bits / 8); 1762 1763 arg_offset += arg->n_bits / 8; 1764 } 1765 1766 tokens += 2 + action->info.n_args * 2; 1767 n_tokens -= 2 + action->info.n_args * 2; 1768 1769 other: 1770 if (n_tokens) 1771 goto error; 1772 1773 free(s0); 1774 return entry; 1775 1776 error: 1777 table_entry_free(entry); 1778 free(s0); 1779 if (is_blank_or_comment) 1780 *is_blank_or_comment = blank_or_comment; 1781 return NULL; 1782 } 1783 1784 static void 1785 table_entry_printf(FILE *f, 1786 struct rte_swx_ctl_pipeline *ctl, 1787 struct table *table, 1788 struct rte_swx_table_entry *entry) 1789 { 1790 struct action *action = &ctl->actions[entry->action_id]; 1791 uint32_t i; 1792 1793 fprintf(f, "match "); 1794 for (i = 0; i < table->params.key_size; i++) 1795 fprintf(f, "%02x", entry->key[i]); 1796 1797 if (entry->key_mask) { 1798 fprintf(f, "/"); 1799 for (i = 0; i < table->params.key_size; i++) 1800 fprintf(f, "%02x", entry->key_mask[i]); 1801 } 1802 1803 fprintf(f, " priority %u", entry->key_priority); 1804 1805 fprintf(f, " action %s ", action->info.name); 1806 for (i = 0; i < action->data_size; i++) 1807 fprintf(f, "%02x", entry->action_data[i]); 1808 1809 fprintf(f, "\n"); 1810 } 1811 1812 int 1813 rte_swx_ctl_pipeline_table_fprintf(FILE *f, 1814 struct rte_swx_ctl_pipeline *ctl, 1815 const char *table_name) 1816 { 1817 struct table *table; 1818 struct rte_swx_table_entry *entry; 1819 uint32_t n_entries = 0, i; 1820 1821 if (!f || !ctl || !table_name || !table_name[0]) 1822 return -EINVAL; 1823 1824 table = table_find(ctl, table_name); 1825 if (!table) 1826 return -EINVAL; 1827 1828 /* Table. */ 1829 fprintf(f, "# Table %s: key size %u bytes, key offset %u, key mask [", 1830 table->info.name, 1831 table->params.key_size, 1832 table->params.key_offset); 1833 1834 for (i = 0; i < table->params.key_size; i++) 1835 fprintf(f, "%02x", table->params.key_mask0[i]); 1836 1837 fprintf(f, "], action data size %u bytes\n", 1838 table->params.action_data_size); 1839 1840 /* Table entries. */ 1841 TAILQ_FOREACH(entry, &table->entries, node) { 1842 table_entry_printf(f, ctl, table, entry); 1843 n_entries++; 1844 } 1845 1846 TAILQ_FOREACH(entry, &table->pending_modify0, node) { 1847 table_entry_printf(f, ctl, table, entry); 1848 n_entries++; 1849 } 1850 1851 TAILQ_FOREACH(entry, &table->pending_delete, node) { 1852 table_entry_printf(f, ctl, table, entry); 1853 n_entries++; 1854 } 1855 1856 fprintf(f, "# Table %s currently has %u entries.\n", 1857 table_name, 1858 n_entries); 1859 return 0; 1860 } 1861