1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2020 Intel Corporation 3 */ 4 #include <stdint.h> 5 #include <stdlib.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include <errno.h> 9 10 #include "rte_swx_pipeline.h" 11 #include "rte_swx_ctl.h" 12 13 #define MAX_LINE_LENGTH RTE_SWX_INSTRUCTION_SIZE 14 #define MAX_TOKENS RTE_SWX_INSTRUCTION_TOKENS_MAX 15 16 #define STRUCT_BLOCK 0 17 #define ACTION_BLOCK 1 18 #define TABLE_BLOCK 2 19 #define TABLE_KEY_BLOCK 3 20 #define TABLE_ACTIONS_BLOCK 4 21 #define APPLY_BLOCK 5 22 23 /* 24 * extobj. 25 * 26 * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ] 27 */ 28 struct extobj_spec { 29 char *name; 30 char *extern_type_name; 31 char *pragma; 32 }; 33 34 static void 35 extobj_spec_free(struct extobj_spec *s) 36 { 37 if (!s) 38 return; 39 40 free(s->name); 41 s->name = NULL; 42 43 free(s->extern_type_name); 44 s->extern_type_name = NULL; 45 46 free(s->pragma); 47 s->pragma = NULL; 48 } 49 50 static int 51 extobj_statement_parse(struct extobj_spec *s, 52 char **tokens, 53 uint32_t n_tokens, 54 uint32_t n_lines, 55 uint32_t *err_line, 56 const char **err_msg) 57 { 58 /* Check format. */ 59 if (((n_tokens != 4) && (n_tokens != 6)) || 60 ((n_tokens == 4) && strcmp(tokens[2], "instanceof")) || 61 ((n_tokens == 6) && (strcmp(tokens[2], "instanceof") || 62 strcmp(tokens[4], "pragma")))) { 63 if (err_line) 64 *err_line = n_lines; 65 if (err_msg) 66 *err_msg = "Invalid extobj statement."; 67 return -EINVAL; 68 } 69 70 /* spec. */ 71 s->name = strdup(tokens[1]); 72 s->extern_type_name = strdup(tokens[3]); 73 s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL; 74 75 if (!s->name || 76 !s->extern_type_name || 77 ((n_tokens == 6) && !s->pragma)) { 78 free(s->name); 79 free(s->extern_type_name); 80 free(s->pragma); 81 82 if (err_line) 83 *err_line = n_lines; 84 if (err_msg) 85 *err_msg = "Memory allocation failed."; 86 return -ENOMEM; 87 } 88 89 return 0; 90 } 91 92 /* 93 * struct. 94 * 95 * struct STRUCT_TYPE_NAME { 96 * bit<SIZE> FIELD_NAME 97 * ... 98 * } 99 */ 100 struct struct_spec { 101 char *name; 102 struct rte_swx_field_params *fields; 103 uint32_t n_fields; 104 }; 105 106 static void 107 struct_spec_free(struct struct_spec *s) 108 { 109 uint32_t i; 110 111 if (!s) 112 return; 113 114 free(s->name); 115 s->name = NULL; 116 117 for (i = 0; i < s->n_fields; i++) { 118 uintptr_t name = (uintptr_t)s->fields[i].name; 119 120 free((void *)name); 121 } 122 123 free(s->fields); 124 s->fields = NULL; 125 126 s->n_fields = 0; 127 } 128 129 static int 130 struct_statement_parse(struct struct_spec *s, 131 uint32_t *block_mask, 132 char **tokens, 133 uint32_t n_tokens, 134 uint32_t n_lines, 135 uint32_t *err_line, 136 const char **err_msg) 137 { 138 /* Check format. */ 139 if ((n_tokens != 3) || strcmp(tokens[2], "{")) { 140 if (err_line) 141 *err_line = n_lines; 142 if (err_msg) 143 *err_msg = "Invalid struct statement."; 144 return -EINVAL; 145 } 146 147 /* spec. */ 148 s->name = strdup(tokens[1]); 149 if (!s->name) { 150 if (err_line) 151 *err_line = n_lines; 152 if (err_msg) 153 *err_msg = "Memory allocation failed."; 154 return -ENOMEM; 155 } 156 157 /* block_mask. */ 158 *block_mask |= 1 << STRUCT_BLOCK; 159 160 return 0; 161 } 162 163 static int 164 struct_block_parse(struct struct_spec *s, 165 uint32_t *block_mask, 166 char **tokens, 167 uint32_t n_tokens, 168 uint32_t n_lines, 169 uint32_t *err_line, 170 const char **err_msg) 171 { 172 struct rte_swx_field_params *new_fields; 173 char *p = tokens[0], *name; 174 uint32_t n_bits; 175 176 /* Handle end of block. */ 177 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 178 *block_mask &= ~(1 << STRUCT_BLOCK); 179 return 0; 180 } 181 182 /* Check format. */ 183 if ((n_tokens != 2) || 184 (strlen(p) < 6) || 185 (p[0] != 'b') || 186 (p[1] != 'i') || 187 (p[2] != 't') || 188 (p[3] != '<') || 189 (p[strlen(p) - 1] != '>')) { 190 if (err_line) 191 *err_line = n_lines; 192 if (err_msg) 193 *err_msg = "Invalid struct field statement."; 194 return -EINVAL; 195 } 196 197 /* Remove the "bit<" and ">". */ 198 p[strlen(p) - 1] = 0; 199 p += 4; 200 201 n_bits = strtoul(p, &p, 0); 202 if ((p[0]) || 203 !n_bits || 204 (n_bits % 8) || 205 (n_bits > 64)) { 206 if (err_line) 207 *err_line = n_lines; 208 if (err_msg) 209 *err_msg = "Invalid struct field size."; 210 return -EINVAL; 211 } 212 213 /* spec. */ 214 name = strdup(tokens[1]); 215 if (!name) { 216 if (err_line) 217 *err_line = n_lines; 218 if (err_msg) 219 *err_msg = "Memory allocation failed."; 220 return -ENOMEM; 221 } 222 223 new_fields = realloc(s->fields, 224 (s->n_fields + 1) * sizeof(struct rte_swx_field_params)); 225 if (!new_fields) { 226 free(name); 227 228 if (err_line) 229 *err_line = n_lines; 230 if (err_msg) 231 *err_msg = "Memory allocation failed."; 232 return -ENOMEM; 233 } 234 235 s->fields = new_fields; 236 s->fields[s->n_fields].name = name; 237 s->fields[s->n_fields].n_bits = n_bits; 238 s->n_fields++; 239 240 return 0; 241 } 242 243 /* 244 * header. 245 * 246 * header HEADER_NAME instanceof STRUCT_TYPE_NAME 247 */ 248 struct header_spec { 249 char *name; 250 char *struct_type_name; 251 }; 252 253 static void 254 header_spec_free(struct header_spec *s) 255 { 256 if (!s) 257 return; 258 259 free(s->name); 260 s->name = NULL; 261 262 free(s->struct_type_name); 263 s->struct_type_name = NULL; 264 } 265 266 static int 267 header_statement_parse(struct header_spec *s, 268 char **tokens, 269 uint32_t n_tokens, 270 uint32_t n_lines, 271 uint32_t *err_line, 272 const char **err_msg) 273 { 274 /* Check format. */ 275 if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) { 276 if (err_line) 277 *err_line = n_lines; 278 if (err_msg) 279 *err_msg = "Invalid header statement."; 280 return -EINVAL; 281 } 282 283 /* spec. */ 284 s->name = strdup(tokens[1]); 285 s->struct_type_name = strdup(tokens[3]); 286 287 if (!s->name || !s->struct_type_name) { 288 free(s->name); 289 free(s->struct_type_name); 290 291 if (err_line) 292 *err_line = n_lines; 293 if (err_msg) 294 *err_msg = "Memory allocation failed."; 295 return -ENOMEM; 296 } 297 298 return 0; 299 } 300 301 /* 302 * metadata. 303 * 304 * metadata instanceof STRUCT_TYPE_NAME 305 */ 306 struct metadata_spec { 307 char *struct_type_name; 308 }; 309 310 static void 311 metadata_spec_free(struct metadata_spec *s) 312 { 313 if (!s) 314 return; 315 316 free(s->struct_type_name); 317 s->struct_type_name = NULL; 318 } 319 320 static int 321 metadata_statement_parse(struct metadata_spec *s, 322 char **tokens, 323 uint32_t n_tokens, 324 uint32_t n_lines, 325 uint32_t *err_line, 326 const char **err_msg) 327 { 328 /* Check format. */ 329 if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) { 330 if (err_line) 331 *err_line = n_lines; 332 if (err_msg) 333 *err_msg = "Invalid metadata statement."; 334 return -EINVAL; 335 } 336 337 /* spec. */ 338 s->struct_type_name = strdup(tokens[2]); 339 if (!s->struct_type_name) { 340 if (err_line) 341 *err_line = n_lines; 342 if (err_msg) 343 *err_msg = "Memory allocation failed."; 344 return -ENOMEM; 345 } 346 347 return 0; 348 } 349 350 /* 351 * action. 352 * 353 * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME { 354 * INSTRUCTION 355 * ... 356 * } 357 */ 358 struct action_spec { 359 char *name; 360 char *args_struct_type_name; 361 const char **instructions; 362 uint32_t n_instructions; 363 }; 364 365 static void 366 action_spec_free(struct action_spec *s) 367 { 368 uint32_t i; 369 370 if (!s) 371 return; 372 373 free(s->name); 374 s->name = NULL; 375 376 free(s->args_struct_type_name); 377 s->args_struct_type_name = NULL; 378 379 for (i = 0; i < s->n_instructions; i++) { 380 uintptr_t instr = (uintptr_t)s->instructions[i]; 381 382 free((void *)instr); 383 } 384 385 free(s->instructions); 386 s->instructions = NULL; 387 388 s->n_instructions = 0; 389 } 390 391 static int 392 action_statement_parse(struct action_spec *s, 393 uint32_t *block_mask, 394 char **tokens, 395 uint32_t n_tokens, 396 uint32_t n_lines, 397 uint32_t *err_line, 398 const char **err_msg) 399 { 400 /* Check format. */ 401 if (((n_tokens != 5) && (n_tokens != 6)) || 402 ((n_tokens == 5) && 403 (strcmp(tokens[2], "args") || 404 strcmp(tokens[3], "none") || 405 strcmp(tokens[4], "{"))) || 406 ((n_tokens == 6) && 407 (strcmp(tokens[2], "args") || 408 strcmp(tokens[3], "instanceof") || 409 strcmp(tokens[5], "{")))) { 410 if (err_line) 411 *err_line = n_lines; 412 if (err_msg) 413 *err_msg = "Invalid action statement."; 414 return -EINVAL; 415 } 416 417 /* spec. */ 418 s->name = strdup(tokens[1]); 419 s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL; 420 421 if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) { 422 if (err_line) 423 *err_line = n_lines; 424 if (err_msg) 425 *err_msg = "Memory allocation failed."; 426 return -ENOMEM; 427 } 428 429 /* block_mask. */ 430 *block_mask |= 1 << ACTION_BLOCK; 431 432 return 0; 433 } 434 435 static int 436 action_block_parse(struct action_spec *s, 437 uint32_t *block_mask, 438 char **tokens, 439 uint32_t n_tokens, 440 uint32_t n_lines, 441 uint32_t *err_line, 442 const char **err_msg) 443 { 444 char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr; 445 const char **new_instructions; 446 uint32_t i; 447 448 /* Handle end of block. */ 449 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 450 *block_mask &= ~(1 << ACTION_BLOCK); 451 return 0; 452 } 453 454 /* spec. */ 455 buffer[0] = 0; 456 for (i = 0; i < n_tokens; i++) { 457 if (i) 458 strcat(buffer, " "); 459 strcat(buffer, tokens[i]); 460 } 461 462 instr = strdup(buffer); 463 if (!instr) { 464 if (err_line) 465 *err_line = n_lines; 466 if (err_msg) 467 *err_msg = "Memory allocation failed."; 468 return -ENOMEM; 469 } 470 471 new_instructions = realloc(s->instructions, 472 (s->n_instructions + 1) * sizeof(char *)); 473 if (!new_instructions) { 474 free(instr); 475 476 if (err_line) 477 *err_line = n_lines; 478 if (err_msg) 479 *err_msg = "Memory allocation failed."; 480 return -ENOMEM; 481 } 482 483 s->instructions = new_instructions; 484 s->instructions[s->n_instructions] = instr; 485 s->n_instructions++; 486 487 return 0; 488 } 489 490 /* 491 * table. 492 * 493 * table { 494 * key { 495 * MATCH_FIELD_NAME exact | wildcard | lpm 496 * ... 497 * } 498 * actions { 499 * ACTION_NAME 500 * ... 501 * } 502 * default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ] 503 * instanceof TABLE_TYPE_NAME 504 * pragma ARGS 505 * size SIZE 506 * } 507 */ 508 struct table_spec { 509 char *name; 510 struct rte_swx_pipeline_table_params params; 511 char *recommended_table_type_name; 512 char *args; 513 uint32_t size; 514 }; 515 516 static void 517 table_spec_free(struct table_spec *s) 518 { 519 uintptr_t default_action_name; 520 uint32_t i; 521 522 if (!s) 523 return; 524 525 free(s->name); 526 s->name = NULL; 527 528 for (i = 0; i < s->params.n_fields; i++) { 529 uintptr_t name = (uintptr_t)s->params.fields[i].name; 530 531 free((void *)name); 532 } 533 534 free(s->params.fields); 535 s->params.fields = NULL; 536 537 s->params.n_fields = 0; 538 539 for (i = 0; i < s->params.n_actions; i++) { 540 uintptr_t name = (uintptr_t)s->params.action_names[i]; 541 542 free((void *)name); 543 } 544 545 free(s->params.action_names); 546 s->params.action_names = NULL; 547 548 s->params.n_actions = 0; 549 550 default_action_name = (uintptr_t)s->params.default_action_name; 551 free((void *)default_action_name); 552 s->params.default_action_name = NULL; 553 554 free(s->params.default_action_data); 555 s->params.default_action_data = NULL; 556 557 s->params.default_action_is_const = 0; 558 559 free(s->recommended_table_type_name); 560 s->recommended_table_type_name = NULL; 561 562 free(s->args); 563 s->args = NULL; 564 565 s->size = 0; 566 } 567 568 static int 569 table_key_statement_parse(uint32_t *block_mask, 570 char **tokens, 571 uint32_t n_tokens, 572 uint32_t n_lines, 573 uint32_t *err_line, 574 const char **err_msg) 575 { 576 /* Check format. */ 577 if ((n_tokens != 2) || strcmp(tokens[1], "{")) { 578 if (err_line) 579 *err_line = n_lines; 580 if (err_msg) 581 *err_msg = "Invalid key statement."; 582 return -EINVAL; 583 } 584 585 /* block_mask. */ 586 *block_mask |= 1 << TABLE_KEY_BLOCK; 587 588 return 0; 589 } 590 591 static int 592 table_key_block_parse(struct table_spec *s, 593 uint32_t *block_mask, 594 char **tokens, 595 uint32_t n_tokens, 596 uint32_t n_lines, 597 uint32_t *err_line, 598 const char **err_msg) 599 { 600 struct rte_swx_match_field_params *new_fields; 601 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD; 602 char *name; 603 604 /* Handle end of block. */ 605 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 606 *block_mask &= ~(1 << TABLE_KEY_BLOCK); 607 return 0; 608 } 609 610 /* Check input arguments. */ 611 if ((n_tokens != 2) || 612 (strcmp(tokens[1], "exact") && 613 strcmp(tokens[1], "wildcard") && 614 strcmp(tokens[1], "lpm"))) { 615 if (err_line) 616 *err_line = n_lines; 617 if (err_msg) 618 *err_msg = "Invalid match field statement."; 619 return -EINVAL; 620 } 621 622 if (!strcmp(tokens[1], "wildcard")) 623 match_type = RTE_SWX_TABLE_MATCH_WILDCARD; 624 if (!strcmp(tokens[1], "lpm")) 625 match_type = RTE_SWX_TABLE_MATCH_LPM; 626 if (!strcmp(tokens[1], "exact")) 627 match_type = RTE_SWX_TABLE_MATCH_EXACT; 628 629 name = strdup(tokens[0]); 630 if (!name) { 631 if (err_line) 632 *err_line = n_lines; 633 if (err_msg) 634 *err_msg = "Memory allocation failed."; 635 return -ENOMEM; 636 } 637 638 new_fields = realloc(s->params.fields, 639 (s->params.n_fields + 1) * sizeof(struct rte_swx_match_field_params)); 640 if (!new_fields) { 641 free(name); 642 643 if (err_line) 644 *err_line = n_lines; 645 if (err_msg) 646 *err_msg = "Memory allocation failed."; 647 return -ENOMEM; 648 } 649 650 s->params.fields = new_fields; 651 s->params.fields[s->params.n_fields].name = name; 652 s->params.fields[s->params.n_fields].match_type = match_type; 653 s->params.n_fields++; 654 655 return 0; 656 } 657 658 static int 659 table_actions_statement_parse(uint32_t *block_mask, 660 char **tokens, 661 uint32_t n_tokens, 662 uint32_t n_lines, 663 uint32_t *err_line, 664 const char **err_msg) 665 { 666 /* Check format. */ 667 if ((n_tokens != 2) || strcmp(tokens[1], "{")) { 668 if (err_line) 669 *err_line = n_lines; 670 if (err_msg) 671 *err_msg = "Invalid actions statement."; 672 return -EINVAL; 673 } 674 675 /* block_mask. */ 676 *block_mask |= 1 << TABLE_ACTIONS_BLOCK; 677 678 return 0; 679 } 680 681 static int 682 table_actions_block_parse(struct table_spec *s, 683 uint32_t *block_mask, 684 char **tokens, 685 uint32_t n_tokens, 686 uint32_t n_lines, 687 uint32_t *err_line, 688 const char **err_msg) 689 { 690 const char **new_action_names; 691 char *name; 692 693 /* Handle end of block. */ 694 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 695 *block_mask &= ~(1 << TABLE_ACTIONS_BLOCK); 696 return 0; 697 } 698 699 /* Check input arguments. */ 700 if (n_tokens != 1) { 701 if (err_line) 702 *err_line = n_lines; 703 if (err_msg) 704 *err_msg = "Invalid action name statement."; 705 return -EINVAL; 706 } 707 708 name = strdup(tokens[0]); 709 if (!name) { 710 if (err_line) 711 *err_line = n_lines; 712 if (err_msg) 713 *err_msg = "Memory allocation failed."; 714 return -ENOMEM; 715 } 716 717 new_action_names = realloc(s->params.action_names, 718 (s->params.n_actions + 1) * sizeof(char *)); 719 if (!new_action_names) { 720 free(name); 721 722 if (err_line) 723 *err_line = n_lines; 724 if (err_msg) 725 *err_msg = "Memory allocation failed."; 726 return -ENOMEM; 727 } 728 729 s->params.action_names = new_action_names; 730 s->params.action_names[s->params.n_actions] = name; 731 s->params.n_actions++; 732 733 return 0; 734 } 735 736 static int 737 table_statement_parse(struct table_spec *s, 738 uint32_t *block_mask, 739 char **tokens, 740 uint32_t n_tokens, 741 uint32_t n_lines, 742 uint32_t *err_line, 743 const char **err_msg) 744 { 745 /* Check format. */ 746 if ((n_tokens != 3) || strcmp(tokens[2], "{")) { 747 if (err_line) 748 *err_line = n_lines; 749 if (err_msg) 750 *err_msg = "Invalid table statement."; 751 return -EINVAL; 752 } 753 754 /* spec. */ 755 s->name = strdup(tokens[1]); 756 if (!s->name) { 757 if (err_line) 758 *err_line = n_lines; 759 if (err_msg) 760 *err_msg = "Memory allocation failed."; 761 return -ENOMEM; 762 } 763 764 /* block_mask. */ 765 *block_mask |= 1 << TABLE_BLOCK; 766 767 return 0; 768 } 769 770 static int 771 table_block_parse(struct table_spec *s, 772 uint32_t *block_mask, 773 char **tokens, 774 uint32_t n_tokens, 775 uint32_t n_lines, 776 uint32_t *err_line, 777 const char **err_msg) 778 { 779 if (*block_mask & (1 << TABLE_KEY_BLOCK)) 780 return table_key_block_parse(s, 781 block_mask, 782 tokens, 783 n_tokens, 784 n_lines, 785 err_line, 786 err_msg); 787 788 if (*block_mask & (1 << TABLE_ACTIONS_BLOCK)) 789 return table_actions_block_parse(s, 790 block_mask, 791 tokens, 792 n_tokens, 793 n_lines, 794 err_line, 795 err_msg); 796 797 /* Handle end of block. */ 798 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 799 *block_mask &= ~(1 << TABLE_BLOCK); 800 return 0; 801 } 802 803 if (!strcmp(tokens[0], "key")) 804 return table_key_statement_parse(block_mask, 805 tokens, 806 n_tokens, 807 n_lines, 808 err_line, 809 err_msg); 810 811 if (!strcmp(tokens[0], "actions")) 812 return table_actions_statement_parse(block_mask, 813 tokens, 814 n_tokens, 815 n_lines, 816 err_line, 817 err_msg); 818 819 if (!strcmp(tokens[0], "default_action")) { 820 if (((n_tokens != 4) && (n_tokens != 5)) || 821 strcmp(tokens[2], "args") || 822 strcmp(tokens[3], "none") || 823 ((n_tokens == 5) && strcmp(tokens[4], "const"))) { 824 if (err_line) 825 *err_line = n_lines; 826 if (err_msg) 827 *err_msg = "Invalid default_action statement."; 828 return -EINVAL; 829 } 830 831 if (s->params.default_action_name) { 832 if (err_line) 833 *err_line = n_lines; 834 if (err_msg) 835 *err_msg = "Duplicate default_action stmt."; 836 return -EINVAL; 837 } 838 839 s->params.default_action_name = strdup(tokens[1]); 840 if (!s->params.default_action_name) { 841 if (err_line) 842 *err_line = n_lines; 843 if (err_msg) 844 *err_msg = "Memory allocation failed."; 845 return -ENOMEM; 846 } 847 848 if (n_tokens == 5) 849 s->params.default_action_is_const = 1; 850 851 return 0; 852 } 853 854 if (!strcmp(tokens[0], "instanceof")) { 855 if (n_tokens != 2) { 856 if (err_line) 857 *err_line = n_lines; 858 if (err_msg) 859 *err_msg = "Invalid instanceof statement."; 860 return -EINVAL; 861 } 862 863 if (s->recommended_table_type_name) { 864 if (err_line) 865 *err_line = n_lines; 866 if (err_msg) 867 *err_msg = "Duplicate instanceof statement."; 868 return -EINVAL; 869 } 870 871 s->recommended_table_type_name = strdup(tokens[1]); 872 if (!s->recommended_table_type_name) { 873 if (err_line) 874 *err_line = n_lines; 875 if (err_msg) 876 *err_msg = "Memory allocation failed."; 877 return -ENOMEM; 878 } 879 880 return 0; 881 } 882 883 if (!strcmp(tokens[0], "pragma")) { 884 if (n_tokens != 2) { 885 if (err_line) 886 *err_line = n_lines; 887 if (err_msg) 888 *err_msg = "Invalid pragma statement."; 889 return -EINVAL; 890 } 891 892 if (s->args) { 893 if (err_line) 894 *err_line = n_lines; 895 if (err_msg) 896 *err_msg = "Duplicate pragma statement."; 897 return -EINVAL; 898 } 899 900 s->args = strdup(tokens[1]); 901 if (!s->args) { 902 if (err_line) 903 *err_line = n_lines; 904 if (err_msg) 905 *err_msg = "Memory allocation failed."; 906 return -ENOMEM; 907 } 908 909 return 0; 910 } 911 912 if (!strcmp(tokens[0], "size")) { 913 char *p = tokens[1]; 914 915 if (n_tokens != 2) { 916 if (err_line) 917 *err_line = n_lines; 918 if (err_msg) 919 *err_msg = "Invalid pragma statement."; 920 return -EINVAL; 921 } 922 923 s->size = strtoul(p, &p, 0); 924 if (p[0]) { 925 if (err_line) 926 *err_line = n_lines; 927 if (err_msg) 928 *err_msg = "Invalid size argument."; 929 return -EINVAL; 930 } 931 932 return 0; 933 } 934 935 /* Anything else. */ 936 if (err_line) 937 *err_line = n_lines; 938 if (err_msg) 939 *err_msg = "Invalid statement."; 940 return -EINVAL; 941 } 942 943 /* 944 * regarray. 945 * 946 * regarray NAME size SIZE initval INITVAL 947 */ 948 struct regarray_spec { 949 char *name; 950 uint64_t init_val; 951 uint32_t size; 952 }; 953 954 static void 955 regarray_spec_free(struct regarray_spec *s) 956 { 957 if (!s) 958 return; 959 960 free(s->name); 961 s->name = NULL; 962 } 963 964 static int 965 regarray_statement_parse(struct regarray_spec *s, 966 char **tokens, 967 uint32_t n_tokens, 968 uint32_t n_lines, 969 uint32_t *err_line, 970 const char **err_msg) 971 { 972 char *p; 973 974 /* Check format. */ 975 if ((n_tokens != 6) || 976 strcmp(tokens[2], "size") || 977 strcmp(tokens[4], "initval")) { 978 if (err_line) 979 *err_line = n_lines; 980 if (err_msg) 981 *err_msg = "Invalid regarray statement."; 982 return -EINVAL; 983 } 984 985 /* spec. */ 986 s->name = strdup(tokens[1]); 987 if (!s->name) { 988 if (err_line) 989 *err_line = n_lines; 990 if (err_msg) 991 *err_msg = "Memory allocation failed."; 992 return -ENOMEM; 993 } 994 995 p = tokens[3]; 996 s->size = strtoul(p, &p, 0); 997 if (p[0] || !s->size) { 998 if (err_line) 999 *err_line = n_lines; 1000 if (err_msg) 1001 *err_msg = "Invalid size argument."; 1002 return -EINVAL; 1003 } 1004 1005 p = tokens[5]; 1006 s->init_val = strtoull(p, &p, 0); 1007 if (p[0]) { 1008 if (err_line) 1009 *err_line = n_lines; 1010 if (err_msg) 1011 *err_msg = "Invalid initval argument."; 1012 return -EINVAL; 1013 } 1014 1015 return 0; 1016 } 1017 1018 /* 1019 * metarray. 1020 * 1021 * metarray NAME size SIZE 1022 */ 1023 struct metarray_spec { 1024 char *name; 1025 uint32_t size; 1026 }; 1027 1028 static void 1029 metarray_spec_free(struct metarray_spec *s) 1030 { 1031 if (!s) 1032 return; 1033 1034 free(s->name); 1035 s->name = NULL; 1036 } 1037 1038 static int 1039 metarray_statement_parse(struct metarray_spec *s, 1040 char **tokens, 1041 uint32_t n_tokens, 1042 uint32_t n_lines, 1043 uint32_t *err_line, 1044 const char **err_msg) 1045 { 1046 char *p; 1047 1048 /* Check format. */ 1049 if ((n_tokens != 4) || strcmp(tokens[2], "size")) { 1050 if (err_line) 1051 *err_line = n_lines; 1052 if (err_msg) 1053 *err_msg = "Invalid metarray statement."; 1054 return -EINVAL; 1055 } 1056 1057 /* spec. */ 1058 s->name = strdup(tokens[1]); 1059 if (!s->name) { 1060 if (err_line) 1061 *err_line = n_lines; 1062 if (err_msg) 1063 *err_msg = "Memory allocation failed."; 1064 return -ENOMEM; 1065 } 1066 1067 p = tokens[3]; 1068 s->size = strtoul(p, &p, 0); 1069 if (p[0] || !s->size) { 1070 if (err_line) 1071 *err_line = n_lines; 1072 if (err_msg) 1073 *err_msg = "Invalid size argument."; 1074 return -EINVAL; 1075 } 1076 1077 return 0; 1078 } 1079 1080 /* 1081 * apply. 1082 * 1083 * apply { 1084 * INSTRUCTION 1085 * ... 1086 * } 1087 */ 1088 struct apply_spec { 1089 const char **instructions; 1090 uint32_t n_instructions; 1091 }; 1092 1093 static void 1094 apply_spec_free(struct apply_spec *s) 1095 { 1096 uint32_t i; 1097 1098 if (!s) 1099 return; 1100 1101 for (i = 0; i < s->n_instructions; i++) { 1102 uintptr_t instr = (uintptr_t)s->instructions[i]; 1103 1104 free((void *)instr); 1105 } 1106 1107 free(s->instructions); 1108 s->instructions = NULL; 1109 1110 s->n_instructions = 0; 1111 } 1112 1113 static int 1114 apply_statement_parse(uint32_t *block_mask, 1115 char **tokens, 1116 uint32_t n_tokens, 1117 uint32_t n_lines, 1118 uint32_t *err_line, 1119 const char **err_msg) 1120 { 1121 /* Check format. */ 1122 if ((n_tokens != 2) || strcmp(tokens[1], "{")) { 1123 if (err_line) 1124 *err_line = n_lines; 1125 if (err_msg) 1126 *err_msg = "Invalid apply statement."; 1127 return -EINVAL; 1128 } 1129 1130 /* block_mask. */ 1131 *block_mask |= 1 << APPLY_BLOCK; 1132 1133 return 0; 1134 } 1135 1136 static int 1137 apply_block_parse(struct apply_spec *s, 1138 uint32_t *block_mask, 1139 char **tokens, 1140 uint32_t n_tokens, 1141 uint32_t n_lines, 1142 uint32_t *err_line, 1143 const char **err_msg) 1144 { 1145 char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr; 1146 const char **new_instructions; 1147 uint32_t i; 1148 1149 /* Handle end of block. */ 1150 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 1151 *block_mask &= ~(1 << APPLY_BLOCK); 1152 return 0; 1153 } 1154 1155 /* spec. */ 1156 buffer[0] = 0; 1157 for (i = 0; i < n_tokens; i++) { 1158 if (i) 1159 strcat(buffer, " "); 1160 strcat(buffer, tokens[i]); 1161 } 1162 1163 instr = strdup(buffer); 1164 if (!instr) { 1165 if (err_line) 1166 *err_line = n_lines; 1167 if (err_msg) 1168 *err_msg = "Memory allocation failed."; 1169 return -ENOMEM; 1170 } 1171 1172 new_instructions = realloc(s->instructions, 1173 (s->n_instructions + 1) * sizeof(char *)); 1174 if (!new_instructions) { 1175 free(instr); 1176 1177 if (err_line) 1178 *err_line = n_lines; 1179 if (err_msg) 1180 *err_msg = "Memory allocation failed."; 1181 return -ENOMEM; 1182 } 1183 1184 s->instructions = new_instructions; 1185 s->instructions[s->n_instructions] = instr; 1186 s->n_instructions++; 1187 1188 return 0; 1189 } 1190 1191 /* 1192 * Pipeline. 1193 */ 1194 int 1195 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p, 1196 FILE *spec, 1197 uint32_t *err_line, 1198 const char **err_msg) 1199 { 1200 struct extobj_spec extobj_spec = {0}; 1201 struct struct_spec struct_spec = {0}; 1202 struct header_spec header_spec = {0}; 1203 struct metadata_spec metadata_spec = {0}; 1204 struct action_spec action_spec = {0}; 1205 struct table_spec table_spec = {0}; 1206 struct regarray_spec regarray_spec = {0}; 1207 struct metarray_spec metarray_spec = {0}; 1208 struct apply_spec apply_spec = {0}; 1209 uint32_t n_lines; 1210 uint32_t block_mask = 0; 1211 int status; 1212 1213 /* Check the input arguments. */ 1214 if (!p) { 1215 if (err_line) 1216 *err_line = 0; 1217 if (err_msg) 1218 *err_msg = "Null pipeline arument."; 1219 status = -EINVAL; 1220 goto error; 1221 } 1222 1223 if (!spec) { 1224 if (err_line) 1225 *err_line = 0; 1226 if (err_msg) 1227 *err_msg = "Null specification file argument."; 1228 status = -EINVAL; 1229 goto error; 1230 } 1231 1232 for (n_lines = 1; ; n_lines++) { 1233 char line[MAX_LINE_LENGTH]; 1234 char *tokens[MAX_TOKENS], *ptr = line; 1235 uint32_t n_tokens = 0; 1236 1237 /* Read next line. */ 1238 if (!fgets(line, sizeof(line), spec)) 1239 break; 1240 1241 /* Parse the line into tokens. */ 1242 for ( ; ; ) { 1243 char *token; 1244 1245 /* Get token. */ 1246 token = strtok_r(ptr, " \f\n\r\t\v", &ptr); 1247 if (!token) 1248 break; 1249 1250 /* Handle comments. */ 1251 if ((token[0] == '#') || 1252 (token[0] == ';') || 1253 ((token[0] == '/') && (token[1] == '/'))) { 1254 break; 1255 } 1256 1257 /* Handle excessively long lines. */ 1258 if (n_tokens >= MAX_TOKENS) { 1259 if (err_line) 1260 *err_line = n_lines; 1261 if (err_msg) 1262 *err_msg = "Too many tokens."; 1263 status = -EINVAL; 1264 goto error; 1265 } 1266 1267 /* Handle excessively long tokens. */ 1268 if (strnlen(token, RTE_SWX_NAME_SIZE) >= 1269 RTE_SWX_NAME_SIZE) { 1270 if (err_line) 1271 *err_line = n_lines; 1272 if (err_msg) 1273 *err_msg = "Token too big."; 1274 status = -EINVAL; 1275 goto error; 1276 } 1277 1278 /* Save token. */ 1279 tokens[n_tokens] = token; 1280 n_tokens++; 1281 } 1282 1283 /* Handle empty lines. */ 1284 if (!n_tokens) 1285 continue; 1286 1287 /* struct block. */ 1288 if (block_mask & (1 << STRUCT_BLOCK)) { 1289 status = struct_block_parse(&struct_spec, 1290 &block_mask, 1291 tokens, 1292 n_tokens, 1293 n_lines, 1294 err_line, 1295 err_msg); 1296 if (status) 1297 goto error; 1298 1299 if (block_mask & (1 << STRUCT_BLOCK)) 1300 continue; 1301 1302 /* End of block. */ 1303 status = rte_swx_pipeline_struct_type_register(p, 1304 struct_spec.name, 1305 struct_spec.fields, 1306 struct_spec.n_fields); 1307 if (status) { 1308 if (err_line) 1309 *err_line = n_lines; 1310 if (err_msg) 1311 *err_msg = "Struct registration error."; 1312 goto error; 1313 } 1314 1315 struct_spec_free(&struct_spec); 1316 1317 continue; 1318 } 1319 1320 /* action block. */ 1321 if (block_mask & (1 << ACTION_BLOCK)) { 1322 status = action_block_parse(&action_spec, 1323 &block_mask, 1324 tokens, 1325 n_tokens, 1326 n_lines, 1327 err_line, 1328 err_msg); 1329 if (status) 1330 goto error; 1331 1332 if (block_mask & (1 << ACTION_BLOCK)) 1333 continue; 1334 1335 /* End of block. */ 1336 status = rte_swx_pipeline_action_config(p, 1337 action_spec.name, 1338 action_spec.args_struct_type_name, 1339 action_spec.instructions, 1340 action_spec.n_instructions); 1341 if (status) { 1342 if (err_line) 1343 *err_line = n_lines; 1344 if (err_msg) 1345 *err_msg = "Action config error."; 1346 goto error; 1347 } 1348 1349 action_spec_free(&action_spec); 1350 1351 continue; 1352 } 1353 1354 /* table block. */ 1355 if (block_mask & (1 << TABLE_BLOCK)) { 1356 status = table_block_parse(&table_spec, 1357 &block_mask, 1358 tokens, 1359 n_tokens, 1360 n_lines, 1361 err_line, 1362 err_msg); 1363 if (status) 1364 goto error; 1365 1366 if (block_mask & (1 << TABLE_BLOCK)) 1367 continue; 1368 1369 /* End of block. */ 1370 status = rte_swx_pipeline_table_config(p, 1371 table_spec.name, 1372 &table_spec.params, 1373 table_spec.recommended_table_type_name, 1374 table_spec.args, 1375 table_spec.size); 1376 if (status) { 1377 if (err_line) 1378 *err_line = n_lines; 1379 if (err_msg) 1380 *err_msg = "Table configuration error."; 1381 goto error; 1382 } 1383 1384 table_spec_free(&table_spec); 1385 1386 continue; 1387 } 1388 1389 /* apply block. */ 1390 if (block_mask & (1 << APPLY_BLOCK)) { 1391 status = apply_block_parse(&apply_spec, 1392 &block_mask, 1393 tokens, 1394 n_tokens, 1395 n_lines, 1396 err_line, 1397 err_msg); 1398 if (status) 1399 goto error; 1400 1401 if (block_mask & (1 << APPLY_BLOCK)) 1402 continue; 1403 1404 /* End of block. */ 1405 status = rte_swx_pipeline_instructions_config(p, 1406 apply_spec.instructions, 1407 apply_spec.n_instructions); 1408 if (status) { 1409 if (err_line) 1410 *err_line = n_lines; 1411 if (err_msg) 1412 *err_msg = "Pipeline instructions err."; 1413 goto error; 1414 } 1415 1416 apply_spec_free(&apply_spec); 1417 1418 continue; 1419 } 1420 1421 /* extobj. */ 1422 if (!strcmp(tokens[0], "extobj")) { 1423 status = extobj_statement_parse(&extobj_spec, 1424 tokens, 1425 n_tokens, 1426 n_lines, 1427 err_line, 1428 err_msg); 1429 if (status) 1430 goto error; 1431 1432 status = rte_swx_pipeline_extern_object_config(p, 1433 extobj_spec.name, 1434 extobj_spec.extern_type_name, 1435 extobj_spec.pragma); 1436 if (status) { 1437 if (err_line) 1438 *err_line = n_lines; 1439 if (err_msg) 1440 *err_msg = "Extern object config err."; 1441 goto error; 1442 } 1443 1444 extobj_spec_free(&extobj_spec); 1445 1446 continue; 1447 } 1448 1449 /* struct. */ 1450 if (!strcmp(tokens[0], "struct")) { 1451 status = struct_statement_parse(&struct_spec, 1452 &block_mask, 1453 tokens, 1454 n_tokens, 1455 n_lines, 1456 err_line, 1457 err_msg); 1458 if (status) 1459 goto error; 1460 1461 continue; 1462 } 1463 1464 /* header. */ 1465 if (!strcmp(tokens[0], "header")) { 1466 status = header_statement_parse(&header_spec, 1467 tokens, 1468 n_tokens, 1469 n_lines, 1470 err_line, 1471 err_msg); 1472 if (status) 1473 goto error; 1474 1475 status = rte_swx_pipeline_packet_header_register(p, 1476 header_spec.name, 1477 header_spec.struct_type_name); 1478 if (status) { 1479 if (err_line) 1480 *err_line = n_lines; 1481 if (err_msg) 1482 *err_msg = "Header registration error."; 1483 goto error; 1484 } 1485 1486 header_spec_free(&header_spec); 1487 1488 continue; 1489 } 1490 1491 /* metadata. */ 1492 if (!strcmp(tokens[0], "metadata")) { 1493 status = metadata_statement_parse(&metadata_spec, 1494 tokens, 1495 n_tokens, 1496 n_lines, 1497 err_line, 1498 err_msg); 1499 if (status) 1500 goto error; 1501 1502 status = rte_swx_pipeline_packet_metadata_register(p, 1503 metadata_spec.struct_type_name); 1504 if (status) { 1505 if (err_line) 1506 *err_line = n_lines; 1507 if (err_msg) 1508 *err_msg = "Meta-data reg err."; 1509 goto error; 1510 } 1511 1512 metadata_spec_free(&metadata_spec); 1513 1514 continue; 1515 } 1516 1517 /* action. */ 1518 if (!strcmp(tokens[0], "action")) { 1519 status = action_statement_parse(&action_spec, 1520 &block_mask, 1521 tokens, 1522 n_tokens, 1523 n_lines, 1524 err_line, 1525 err_msg); 1526 if (status) 1527 goto error; 1528 1529 continue; 1530 } 1531 1532 /* table. */ 1533 if (!strcmp(tokens[0], "table")) { 1534 status = table_statement_parse(&table_spec, 1535 &block_mask, 1536 tokens, 1537 n_tokens, 1538 n_lines, 1539 err_line, 1540 err_msg); 1541 if (status) 1542 goto error; 1543 1544 continue; 1545 } 1546 1547 /* regarray. */ 1548 if (!strcmp(tokens[0], "regarray")) { 1549 status = regarray_statement_parse(®array_spec, 1550 tokens, 1551 n_tokens, 1552 n_lines, 1553 err_line, 1554 err_msg); 1555 if (status) 1556 goto error; 1557 1558 status = rte_swx_pipeline_regarray_config(p, 1559 regarray_spec.name, 1560 regarray_spec.size, 1561 regarray_spec.init_val); 1562 if (status) { 1563 if (err_line) 1564 *err_line = n_lines; 1565 if (err_msg) 1566 *err_msg = "Register array configuration error."; 1567 goto error; 1568 } 1569 1570 regarray_spec_free(®array_spec); 1571 1572 continue; 1573 } 1574 1575 /* metarray. */ 1576 if (!strcmp(tokens[0], "metarray")) { 1577 status = metarray_statement_parse(&metarray_spec, 1578 tokens, 1579 n_tokens, 1580 n_lines, 1581 err_line, 1582 err_msg); 1583 if (status) 1584 goto error; 1585 1586 status = rte_swx_pipeline_metarray_config(p, 1587 metarray_spec.name, 1588 metarray_spec.size); 1589 if (status) { 1590 if (err_line) 1591 *err_line = n_lines; 1592 if (err_msg) 1593 *err_msg = "Meter array configuration error."; 1594 goto error; 1595 } 1596 1597 metarray_spec_free(&metarray_spec); 1598 1599 continue; 1600 } 1601 1602 /* apply. */ 1603 if (!strcmp(tokens[0], "apply")) { 1604 status = apply_statement_parse(&block_mask, 1605 tokens, 1606 n_tokens, 1607 n_lines, 1608 err_line, 1609 err_msg); 1610 if (status) 1611 goto error; 1612 1613 continue; 1614 } 1615 1616 /* Anything else. */ 1617 if (err_line) 1618 *err_line = n_lines; 1619 if (err_msg) 1620 *err_msg = "Unknown statement."; 1621 status = -EINVAL; 1622 goto error; 1623 } 1624 1625 /* Handle unfinished block. */ 1626 if (block_mask) { 1627 if (err_line) 1628 *err_line = n_lines; 1629 if (err_msg) 1630 *err_msg = "Missing }."; 1631 status = -EINVAL; 1632 goto error; 1633 } 1634 1635 /* Pipeline build. */ 1636 status = rte_swx_pipeline_build(p); 1637 if (status) { 1638 if (err_line) 1639 *err_line = n_lines; 1640 if (err_msg) 1641 *err_msg = "Pipeline build error."; 1642 goto error; 1643 } 1644 1645 return 0; 1646 1647 error: 1648 extobj_spec_free(&extobj_spec); 1649 struct_spec_free(&struct_spec); 1650 header_spec_free(&header_spec); 1651 metadata_spec_free(&metadata_spec); 1652 action_spec_free(&action_spec); 1653 table_spec_free(&table_spec); 1654 regarray_spec_free(®array_spec); 1655 metarray_spec_free(&metarray_spec); 1656 apply_spec_free(&apply_spec); 1657 return status; 1658 } 1659