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 SELECTOR_BLOCK 5 22 #define SELECTOR_SELECTOR_BLOCK 6 23 #define LEARNER_BLOCK 7 24 #define LEARNER_KEY_BLOCK 8 25 #define LEARNER_ACTIONS_BLOCK 9 26 #define APPLY_BLOCK 10 27 28 /* 29 * extobj. 30 * 31 * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ] 32 */ 33 struct extobj_spec { 34 char *name; 35 char *extern_type_name; 36 char *pragma; 37 }; 38 39 static void 40 extobj_spec_free(struct extobj_spec *s) 41 { 42 if (!s) 43 return; 44 45 free(s->name); 46 s->name = NULL; 47 48 free(s->extern_type_name); 49 s->extern_type_name = NULL; 50 51 free(s->pragma); 52 s->pragma = NULL; 53 } 54 55 static int 56 extobj_statement_parse(struct extobj_spec *s, 57 char **tokens, 58 uint32_t n_tokens, 59 uint32_t n_lines, 60 uint32_t *err_line, 61 const char **err_msg) 62 { 63 /* Check format. */ 64 if (((n_tokens != 4) && (n_tokens != 6)) || 65 ((n_tokens == 4) && strcmp(tokens[2], "instanceof")) || 66 ((n_tokens == 6) && (strcmp(tokens[2], "instanceof") || 67 strcmp(tokens[4], "pragma")))) { 68 if (err_line) 69 *err_line = n_lines; 70 if (err_msg) 71 *err_msg = "Invalid extobj statement."; 72 return -EINVAL; 73 } 74 75 /* spec. */ 76 s->name = strdup(tokens[1]); 77 s->extern_type_name = strdup(tokens[3]); 78 s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL; 79 80 if (!s->name || 81 !s->extern_type_name || 82 ((n_tokens == 6) && !s->pragma)) { 83 free(s->name); 84 free(s->extern_type_name); 85 free(s->pragma); 86 87 if (err_line) 88 *err_line = n_lines; 89 if (err_msg) 90 *err_msg = "Memory allocation failed."; 91 return -ENOMEM; 92 } 93 94 return 0; 95 } 96 97 /* 98 * struct. 99 * 100 * struct STRUCT_TYPE_NAME { 101 * bit<SIZE> | varbit<SIZE> FIELD_NAME 102 * ... 103 * } 104 */ 105 struct struct_spec { 106 char *name; 107 struct rte_swx_field_params *fields; 108 uint32_t n_fields; 109 int varbit; 110 }; 111 112 static void 113 struct_spec_free(struct struct_spec *s) 114 { 115 uint32_t i; 116 117 if (!s) 118 return; 119 120 free(s->name); 121 s->name = NULL; 122 123 for (i = 0; i < s->n_fields; i++) { 124 uintptr_t name = (uintptr_t)s->fields[i].name; 125 126 free((void *)name); 127 } 128 129 free(s->fields); 130 s->fields = NULL; 131 132 s->n_fields = 0; 133 134 s->varbit = 0; 135 } 136 137 static int 138 struct_statement_parse(struct struct_spec *s, 139 uint32_t *block_mask, 140 char **tokens, 141 uint32_t n_tokens, 142 uint32_t n_lines, 143 uint32_t *err_line, 144 const char **err_msg) 145 { 146 /* Check format. */ 147 if ((n_tokens != 3) || strcmp(tokens[2], "{")) { 148 if (err_line) 149 *err_line = n_lines; 150 if (err_msg) 151 *err_msg = "Invalid struct statement."; 152 return -EINVAL; 153 } 154 155 /* spec. */ 156 s->name = strdup(tokens[1]); 157 if (!s->name) { 158 if (err_line) 159 *err_line = n_lines; 160 if (err_msg) 161 *err_msg = "Memory allocation failed."; 162 return -ENOMEM; 163 } 164 165 /* block_mask. */ 166 *block_mask |= 1 << STRUCT_BLOCK; 167 168 return 0; 169 } 170 171 static int 172 struct_block_parse(struct struct_spec *s, 173 uint32_t *block_mask, 174 char **tokens, 175 uint32_t n_tokens, 176 uint32_t n_lines, 177 uint32_t *err_line, 178 const char **err_msg) 179 { 180 struct rte_swx_field_params *new_fields; 181 char *p = tokens[0], *name = NULL; 182 uint32_t n_bits; 183 int varbit = 0, error = 0, error_size_invalid = 0, error_varbit_not_last = 0; 184 185 /* Handle end of block. */ 186 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 187 *block_mask &= ~(1 << STRUCT_BLOCK); 188 return 0; 189 } 190 191 /* Check format. */ 192 if (n_tokens != 2) { 193 error = -EINVAL; 194 goto error; 195 } 196 197 if (s->varbit) { 198 error = -EINVAL; 199 error_varbit_not_last = 1; 200 goto error; 201 } 202 203 if (!strncmp(p, "bit<", strlen("bit<"))) { 204 size_t len = strlen(p); 205 206 if ((len < strlen("bit< >")) || (p[len - 1] != '>')) { 207 error = -EINVAL; 208 goto error; 209 } 210 211 /* Remove the "bit<" and ">". */ 212 p[strlen(p) - 1] = 0; 213 p += strlen("bit<"); 214 } else if (!strncmp(p, "varbit<", strlen("varbit<"))) { 215 size_t len = strlen(p); 216 217 if ((len < strlen("varbit< >")) || (p[len - 1] != '>')) { 218 error = -EINVAL; 219 goto error; 220 } 221 222 /* Remove the "varbit<" and ">". */ 223 p[strlen(p) - 1] = 0; 224 p += strlen("varbit<"); 225 226 /* Set the varbit flag. */ 227 varbit = 1; 228 } else { 229 error = -EINVAL; 230 goto error; 231 } 232 233 n_bits = strtoul(p, &p, 0); 234 if ((p[0]) || 235 !n_bits || 236 (n_bits % 8) || 237 ((n_bits > 64) && !varbit)) { 238 error = -EINVAL; 239 error_size_invalid = 1; 240 goto error; 241 } 242 243 /* spec. */ 244 name = strdup(tokens[1]); 245 if (!name) { 246 error = -ENOMEM; 247 goto error; 248 } 249 250 new_fields = realloc(s->fields, (s->n_fields + 1) * sizeof(struct rte_swx_field_params)); 251 if (!new_fields) { 252 error = -ENOMEM; 253 goto error; 254 } 255 256 s->fields = new_fields; 257 s->fields[s->n_fields].name = name; 258 s->fields[s->n_fields].n_bits = n_bits; 259 s->n_fields++; 260 s->varbit = varbit; 261 262 return 0; 263 264 error: 265 free(name); 266 267 if (err_line) 268 *err_line = n_lines; 269 270 if (err_msg) { 271 *err_msg = "Invalid struct field statement."; 272 273 if ((error == -EINVAL) && error_varbit_not_last) 274 *err_msg = "Varbit field is not the last struct field."; 275 276 if ((error == -EINVAL) && error_size_invalid) 277 *err_msg = "Invalid struct field size."; 278 279 if (error == -ENOMEM) 280 *err_msg = "Memory allocation failed."; 281 } 282 283 return error; 284 } 285 286 /* 287 * header. 288 * 289 * header HEADER_NAME instanceof STRUCT_TYPE_NAME 290 */ 291 struct header_spec { 292 char *name; 293 char *struct_type_name; 294 }; 295 296 static void 297 header_spec_free(struct header_spec *s) 298 { 299 if (!s) 300 return; 301 302 free(s->name); 303 s->name = NULL; 304 305 free(s->struct_type_name); 306 s->struct_type_name = NULL; 307 } 308 309 static int 310 header_statement_parse(struct header_spec *s, 311 char **tokens, 312 uint32_t n_tokens, 313 uint32_t n_lines, 314 uint32_t *err_line, 315 const char **err_msg) 316 { 317 /* Check format. */ 318 if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) { 319 if (err_line) 320 *err_line = n_lines; 321 if (err_msg) 322 *err_msg = "Invalid header statement."; 323 return -EINVAL; 324 } 325 326 /* spec. */ 327 s->name = strdup(tokens[1]); 328 s->struct_type_name = strdup(tokens[3]); 329 330 if (!s->name || !s->struct_type_name) { 331 free(s->name); 332 free(s->struct_type_name); 333 334 if (err_line) 335 *err_line = n_lines; 336 if (err_msg) 337 *err_msg = "Memory allocation failed."; 338 return -ENOMEM; 339 } 340 341 return 0; 342 } 343 344 /* 345 * metadata. 346 * 347 * metadata instanceof STRUCT_TYPE_NAME 348 */ 349 struct metadata_spec { 350 char *struct_type_name; 351 }; 352 353 static void 354 metadata_spec_free(struct metadata_spec *s) 355 { 356 if (!s) 357 return; 358 359 free(s->struct_type_name); 360 s->struct_type_name = NULL; 361 } 362 363 static int 364 metadata_statement_parse(struct metadata_spec *s, 365 char **tokens, 366 uint32_t n_tokens, 367 uint32_t n_lines, 368 uint32_t *err_line, 369 const char **err_msg) 370 { 371 /* Check format. */ 372 if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) { 373 if (err_line) 374 *err_line = n_lines; 375 if (err_msg) 376 *err_msg = "Invalid metadata statement."; 377 return -EINVAL; 378 } 379 380 /* spec. */ 381 s->struct_type_name = strdup(tokens[2]); 382 if (!s->struct_type_name) { 383 if (err_line) 384 *err_line = n_lines; 385 if (err_msg) 386 *err_msg = "Memory allocation failed."; 387 return -ENOMEM; 388 } 389 390 return 0; 391 } 392 393 /* 394 * action. 395 * 396 * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME { 397 * INSTRUCTION 398 * ... 399 * } 400 */ 401 struct action_spec { 402 char *name; 403 char *args_struct_type_name; 404 const char **instructions; 405 uint32_t n_instructions; 406 }; 407 408 static void 409 action_spec_free(struct action_spec *s) 410 { 411 uint32_t i; 412 413 if (!s) 414 return; 415 416 free(s->name); 417 s->name = NULL; 418 419 free(s->args_struct_type_name); 420 s->args_struct_type_name = NULL; 421 422 for (i = 0; i < s->n_instructions; i++) { 423 uintptr_t instr = (uintptr_t)s->instructions[i]; 424 425 free((void *)instr); 426 } 427 428 free(s->instructions); 429 s->instructions = NULL; 430 431 s->n_instructions = 0; 432 } 433 434 static int 435 action_statement_parse(struct action_spec *s, 436 uint32_t *block_mask, 437 char **tokens, 438 uint32_t n_tokens, 439 uint32_t n_lines, 440 uint32_t *err_line, 441 const char **err_msg) 442 { 443 /* Check format. */ 444 if (((n_tokens != 5) && (n_tokens != 6)) || 445 ((n_tokens == 5) && 446 (strcmp(tokens[2], "args") || 447 strcmp(tokens[3], "none") || 448 strcmp(tokens[4], "{"))) || 449 ((n_tokens == 6) && 450 (strcmp(tokens[2], "args") || 451 strcmp(tokens[3], "instanceof") || 452 strcmp(tokens[5], "{")))) { 453 if (err_line) 454 *err_line = n_lines; 455 if (err_msg) 456 *err_msg = "Invalid action statement."; 457 return -EINVAL; 458 } 459 460 /* spec. */ 461 s->name = strdup(tokens[1]); 462 s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL; 463 464 if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) { 465 if (err_line) 466 *err_line = n_lines; 467 if (err_msg) 468 *err_msg = "Memory allocation failed."; 469 return -ENOMEM; 470 } 471 472 /* block_mask. */ 473 *block_mask |= 1 << ACTION_BLOCK; 474 475 return 0; 476 } 477 478 static int 479 action_block_parse(struct action_spec *s, 480 uint32_t *block_mask, 481 char **tokens, 482 uint32_t n_tokens, 483 uint32_t n_lines, 484 uint32_t *err_line, 485 const char **err_msg) 486 { 487 char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr; 488 const char **new_instructions; 489 uint32_t i; 490 491 /* Handle end of block. */ 492 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 493 *block_mask &= ~(1 << ACTION_BLOCK); 494 return 0; 495 } 496 497 /* spec. */ 498 buffer[0] = 0; 499 for (i = 0; i < n_tokens; i++) { 500 if (i) 501 strcat(buffer, " "); 502 strcat(buffer, tokens[i]); 503 } 504 505 instr = strdup(buffer); 506 if (!instr) { 507 if (err_line) 508 *err_line = n_lines; 509 if (err_msg) 510 *err_msg = "Memory allocation failed."; 511 return -ENOMEM; 512 } 513 514 new_instructions = realloc(s->instructions, 515 (s->n_instructions + 1) * sizeof(char *)); 516 if (!new_instructions) { 517 free(instr); 518 519 if (err_line) 520 *err_line = n_lines; 521 if (err_msg) 522 *err_msg = "Memory allocation failed."; 523 return -ENOMEM; 524 } 525 526 s->instructions = new_instructions; 527 s->instructions[s->n_instructions] = instr; 528 s->n_instructions++; 529 530 return 0; 531 } 532 533 /* 534 * table. 535 * 536 * table { 537 * key { 538 * MATCH_FIELD_NAME exact | wildcard | lpm 539 * ... 540 * } 541 * actions { 542 * ACTION_NAME [ @tableonly | @defaultonly ] 543 * ... 544 * } 545 * default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ] 546 * instanceof TABLE_TYPE_NAME 547 * pragma ARGS 548 * size SIZE 549 * } 550 */ 551 struct table_spec { 552 char *name; 553 struct rte_swx_pipeline_table_params params; 554 char *recommended_table_type_name; 555 char *args; 556 uint32_t size; 557 }; 558 559 static void 560 table_spec_free(struct table_spec *s) 561 { 562 uintptr_t default_action_name; 563 uint32_t i; 564 565 if (!s) 566 return; 567 568 free(s->name); 569 s->name = NULL; 570 571 for (i = 0; i < s->params.n_fields; i++) { 572 uintptr_t name = (uintptr_t)s->params.fields[i].name; 573 574 free((void *)name); 575 } 576 577 free(s->params.fields); 578 s->params.fields = NULL; 579 580 s->params.n_fields = 0; 581 582 for (i = 0; i < s->params.n_actions; i++) { 583 uintptr_t name = (uintptr_t)s->params.action_names[i]; 584 585 free((void *)name); 586 } 587 588 free(s->params.action_names); 589 s->params.action_names = NULL; 590 591 s->params.n_actions = 0; 592 593 default_action_name = (uintptr_t)s->params.default_action_name; 594 free((void *)default_action_name); 595 s->params.default_action_name = NULL; 596 597 free(s->params.default_action_data); 598 s->params.default_action_data = NULL; 599 600 free(s->params.action_is_for_table_entries); 601 s->params.action_is_for_table_entries = NULL; 602 603 free(s->params.action_is_for_default_entry); 604 s->params.action_is_for_default_entry = NULL; 605 606 s->params.default_action_is_const = 0; 607 608 free(s->recommended_table_type_name); 609 s->recommended_table_type_name = NULL; 610 611 free(s->args); 612 s->args = NULL; 613 614 s->size = 0; 615 } 616 617 static int 618 table_key_statement_parse(uint32_t *block_mask, 619 char **tokens, 620 uint32_t n_tokens, 621 uint32_t n_lines, 622 uint32_t *err_line, 623 const char **err_msg) 624 { 625 /* Check format. */ 626 if ((n_tokens != 2) || strcmp(tokens[1], "{")) { 627 if (err_line) 628 *err_line = n_lines; 629 if (err_msg) 630 *err_msg = "Invalid key statement."; 631 return -EINVAL; 632 } 633 634 /* block_mask. */ 635 *block_mask |= 1 << TABLE_KEY_BLOCK; 636 637 return 0; 638 } 639 640 static int 641 table_key_block_parse(struct table_spec *s, 642 uint32_t *block_mask, 643 char **tokens, 644 uint32_t n_tokens, 645 uint32_t n_lines, 646 uint32_t *err_line, 647 const char **err_msg) 648 { 649 struct rte_swx_match_field_params *new_fields; 650 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD; 651 char *name; 652 653 /* Handle end of block. */ 654 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 655 *block_mask &= ~(1 << TABLE_KEY_BLOCK); 656 return 0; 657 } 658 659 /* Check input arguments. */ 660 if ((n_tokens != 2) || 661 (strcmp(tokens[1], "exact") && 662 strcmp(tokens[1], "wildcard") && 663 strcmp(tokens[1], "lpm"))) { 664 if (err_line) 665 *err_line = n_lines; 666 if (err_msg) 667 *err_msg = "Invalid match field statement."; 668 return -EINVAL; 669 } 670 671 if (!strcmp(tokens[1], "wildcard")) 672 match_type = RTE_SWX_TABLE_MATCH_WILDCARD; 673 if (!strcmp(tokens[1], "lpm")) 674 match_type = RTE_SWX_TABLE_MATCH_LPM; 675 if (!strcmp(tokens[1], "exact")) 676 match_type = RTE_SWX_TABLE_MATCH_EXACT; 677 678 name = strdup(tokens[0]); 679 if (!name) { 680 if (err_line) 681 *err_line = n_lines; 682 if (err_msg) 683 *err_msg = "Memory allocation failed."; 684 return -ENOMEM; 685 } 686 687 new_fields = realloc(s->params.fields, 688 (s->params.n_fields + 1) * sizeof(struct rte_swx_match_field_params)); 689 if (!new_fields) { 690 free(name); 691 692 if (err_line) 693 *err_line = n_lines; 694 if (err_msg) 695 *err_msg = "Memory allocation failed."; 696 return -ENOMEM; 697 } 698 699 s->params.fields = new_fields; 700 s->params.fields[s->params.n_fields].name = name; 701 s->params.fields[s->params.n_fields].match_type = match_type; 702 s->params.n_fields++; 703 704 return 0; 705 } 706 707 static int 708 table_actions_statement_parse(uint32_t *block_mask, 709 char **tokens, 710 uint32_t n_tokens, 711 uint32_t n_lines, 712 uint32_t *err_line, 713 const char **err_msg) 714 { 715 /* Check format. */ 716 if ((n_tokens != 2) || strcmp(tokens[1], "{")) { 717 if (err_line) 718 *err_line = n_lines; 719 if (err_msg) 720 *err_msg = "Invalid actions statement."; 721 return -EINVAL; 722 } 723 724 /* block_mask. */ 725 *block_mask |= 1 << TABLE_ACTIONS_BLOCK; 726 727 return 0; 728 } 729 730 static int 731 table_actions_block_parse(struct table_spec *s, 732 uint32_t *block_mask, 733 char **tokens, 734 uint32_t n_tokens, 735 uint32_t n_lines, 736 uint32_t *err_line, 737 const char **err_msg) 738 { 739 const char **new_action_names = NULL; 740 int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL; 741 char *name = NULL; 742 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 743 744 /* Handle end of block. */ 745 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 746 *block_mask &= ~(1 << TABLE_ACTIONS_BLOCK); 747 return 0; 748 } 749 750 /* Check input arguments. */ 751 if ((n_tokens > 2) || 752 ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") && 753 strcmp(tokens[1], "@defaultonly"))) { 754 if (err_line) 755 *err_line = n_lines; 756 if (err_msg) 757 *err_msg = "Invalid action name statement."; 758 return -EINVAL; 759 } 760 761 name = strdup(tokens[0]); 762 763 if (n_tokens == 2) { 764 if (!strcmp(tokens[1], "@tableonly")) 765 action_is_for_default_entry = 0; 766 767 if (!strcmp(tokens[1], "@defaultonly")) 768 action_is_for_table_entries = 0; 769 } 770 771 new_action_names = realloc(s->params.action_names, 772 (s->params.n_actions + 1) * sizeof(char *)); 773 new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries, 774 (s->params.n_actions + 1) * sizeof(int)); 775 new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry, 776 (s->params.n_actions + 1) * sizeof(int)); 777 778 if (!name || 779 !new_action_names || 780 !new_action_is_for_table_entries || 781 !new_action_is_for_default_entry) { 782 free(name); 783 free(new_action_names); 784 free(new_action_is_for_table_entries); 785 free(new_action_is_for_default_entry); 786 787 if (err_line) 788 *err_line = n_lines; 789 if (err_msg) 790 *err_msg = "Memory allocation failed."; 791 return -ENOMEM; 792 } 793 794 s->params.action_names = new_action_names; 795 s->params.action_names[s->params.n_actions] = name; 796 797 s->params.action_is_for_table_entries = new_action_is_for_table_entries; 798 s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries; 799 800 s->params.action_is_for_default_entry = new_action_is_for_default_entry; 801 s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry; 802 803 s->params.n_actions++; 804 805 return 0; 806 } 807 808 static int 809 table_statement_parse(struct table_spec *s, 810 uint32_t *block_mask, 811 char **tokens, 812 uint32_t n_tokens, 813 uint32_t n_lines, 814 uint32_t *err_line, 815 const char **err_msg) 816 { 817 /* Check format. */ 818 if ((n_tokens != 3) || strcmp(tokens[2], "{")) { 819 if (err_line) 820 *err_line = n_lines; 821 if (err_msg) 822 *err_msg = "Invalid table statement."; 823 return -EINVAL; 824 } 825 826 /* spec. */ 827 s->name = strdup(tokens[1]); 828 if (!s->name) { 829 if (err_line) 830 *err_line = n_lines; 831 if (err_msg) 832 *err_msg = "Memory allocation failed."; 833 return -ENOMEM; 834 } 835 836 /* block_mask. */ 837 *block_mask |= 1 << TABLE_BLOCK; 838 839 return 0; 840 } 841 842 static int 843 table_block_parse(struct table_spec *s, 844 uint32_t *block_mask, 845 char **tokens, 846 uint32_t n_tokens, 847 uint32_t n_lines, 848 uint32_t *err_line, 849 const char **err_msg) 850 { 851 if (*block_mask & (1 << TABLE_KEY_BLOCK)) 852 return table_key_block_parse(s, 853 block_mask, 854 tokens, 855 n_tokens, 856 n_lines, 857 err_line, 858 err_msg); 859 860 if (*block_mask & (1 << TABLE_ACTIONS_BLOCK)) 861 return table_actions_block_parse(s, 862 block_mask, 863 tokens, 864 n_tokens, 865 n_lines, 866 err_line, 867 err_msg); 868 869 /* Handle end of block. */ 870 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 871 *block_mask &= ~(1 << TABLE_BLOCK); 872 return 0; 873 } 874 875 if (!strcmp(tokens[0], "key")) 876 return table_key_statement_parse(block_mask, 877 tokens, 878 n_tokens, 879 n_lines, 880 err_line, 881 err_msg); 882 883 if (!strcmp(tokens[0], "actions")) 884 return table_actions_statement_parse(block_mask, 885 tokens, 886 n_tokens, 887 n_lines, 888 err_line, 889 err_msg); 890 891 if (!strcmp(tokens[0], "default_action")) { 892 if (((n_tokens != 4) && (n_tokens != 5)) || 893 strcmp(tokens[2], "args") || 894 strcmp(tokens[3], "none") || 895 ((n_tokens == 5) && strcmp(tokens[4], "const"))) { 896 if (err_line) 897 *err_line = n_lines; 898 if (err_msg) 899 *err_msg = "Invalid default_action statement."; 900 return -EINVAL; 901 } 902 903 if (s->params.default_action_name) { 904 if (err_line) 905 *err_line = n_lines; 906 if (err_msg) 907 *err_msg = "Duplicate default_action stmt."; 908 return -EINVAL; 909 } 910 911 s->params.default_action_name = strdup(tokens[1]); 912 if (!s->params.default_action_name) { 913 if (err_line) 914 *err_line = n_lines; 915 if (err_msg) 916 *err_msg = "Memory allocation failed."; 917 return -ENOMEM; 918 } 919 920 if (n_tokens == 5) 921 s->params.default_action_is_const = 1; 922 923 return 0; 924 } 925 926 if (!strcmp(tokens[0], "instanceof")) { 927 if (n_tokens != 2) { 928 if (err_line) 929 *err_line = n_lines; 930 if (err_msg) 931 *err_msg = "Invalid instanceof statement."; 932 return -EINVAL; 933 } 934 935 if (s->recommended_table_type_name) { 936 if (err_line) 937 *err_line = n_lines; 938 if (err_msg) 939 *err_msg = "Duplicate instanceof statement."; 940 return -EINVAL; 941 } 942 943 s->recommended_table_type_name = strdup(tokens[1]); 944 if (!s->recommended_table_type_name) { 945 if (err_line) 946 *err_line = n_lines; 947 if (err_msg) 948 *err_msg = "Memory allocation failed."; 949 return -ENOMEM; 950 } 951 952 return 0; 953 } 954 955 if (!strcmp(tokens[0], "pragma")) { 956 if (n_tokens != 2) { 957 if (err_line) 958 *err_line = n_lines; 959 if (err_msg) 960 *err_msg = "Invalid pragma statement."; 961 return -EINVAL; 962 } 963 964 if (s->args) { 965 if (err_line) 966 *err_line = n_lines; 967 if (err_msg) 968 *err_msg = "Duplicate pragma statement."; 969 return -EINVAL; 970 } 971 972 s->args = strdup(tokens[1]); 973 if (!s->args) { 974 if (err_line) 975 *err_line = n_lines; 976 if (err_msg) 977 *err_msg = "Memory allocation failed."; 978 return -ENOMEM; 979 } 980 981 return 0; 982 } 983 984 if (!strcmp(tokens[0], "size")) { 985 char *p = tokens[1]; 986 987 if (n_tokens != 2) { 988 if (err_line) 989 *err_line = n_lines; 990 if (err_msg) 991 *err_msg = "Invalid pragma statement."; 992 return -EINVAL; 993 } 994 995 s->size = strtoul(p, &p, 0); 996 if (p[0]) { 997 if (err_line) 998 *err_line = n_lines; 999 if (err_msg) 1000 *err_msg = "Invalid size argument."; 1001 return -EINVAL; 1002 } 1003 1004 return 0; 1005 } 1006 1007 /* Anything else. */ 1008 if (err_line) 1009 *err_line = n_lines; 1010 if (err_msg) 1011 *err_msg = "Invalid statement."; 1012 return -EINVAL; 1013 } 1014 1015 /* 1016 * selector. 1017 * 1018 * selector SELECTOR_NAME { 1019 * group_id FIELD_NAME 1020 * selector { 1021 * FIELD_NAME 1022 * ... 1023 * } 1024 * member_id FIELD_NAME 1025 * n_groups N_GROUPS 1026 * n_members_per_group N_MEMBERS_PER_GROUP 1027 * } 1028 */ 1029 struct selector_spec { 1030 char *name; 1031 struct rte_swx_pipeline_selector_params params; 1032 }; 1033 1034 static void 1035 selector_spec_free(struct selector_spec *s) 1036 { 1037 uintptr_t field_name; 1038 uint32_t i; 1039 1040 if (!s) 1041 return; 1042 1043 /* name. */ 1044 free(s->name); 1045 s->name = NULL; 1046 1047 /* params->group_id_field_name. */ 1048 field_name = (uintptr_t)s->params.group_id_field_name; 1049 free((void *)field_name); 1050 s->params.group_id_field_name = NULL; 1051 1052 /* params->selector_field_names. */ 1053 for (i = 0; i < s->params.n_selector_fields; i++) { 1054 field_name = (uintptr_t)s->params.selector_field_names[i]; 1055 1056 free((void *)field_name); 1057 } 1058 1059 free(s->params.selector_field_names); 1060 s->params.selector_field_names = NULL; 1061 1062 s->params.n_selector_fields = 0; 1063 1064 /* params->member_id_field_name. */ 1065 field_name = (uintptr_t)s->params.member_id_field_name; 1066 free((void *)field_name); 1067 s->params.member_id_field_name = NULL; 1068 1069 /* params->n_groups_max. */ 1070 s->params.n_groups_max = 0; 1071 1072 /* params->n_members_per_group_max. */ 1073 s->params.n_members_per_group_max = 0; 1074 } 1075 1076 static int 1077 selector_statement_parse(struct selector_spec *s, 1078 uint32_t *block_mask, 1079 char **tokens, 1080 uint32_t n_tokens, 1081 uint32_t n_lines, 1082 uint32_t *err_line, 1083 const char **err_msg) 1084 { 1085 /* Check format. */ 1086 if ((n_tokens != 3) || strcmp(tokens[2], "{")) { 1087 if (err_line) 1088 *err_line = n_lines; 1089 if (err_msg) 1090 *err_msg = "Invalid selector statement."; 1091 return -EINVAL; 1092 } 1093 1094 /* spec. */ 1095 s->name = strdup(tokens[1]); 1096 if (!s->name) { 1097 if (err_line) 1098 *err_line = n_lines; 1099 if (err_msg) 1100 *err_msg = "Memory allocation failed."; 1101 return -ENOMEM; 1102 } 1103 1104 /* block_mask. */ 1105 *block_mask |= 1 << SELECTOR_BLOCK; 1106 1107 return 0; 1108 } 1109 1110 static int 1111 selector_selector_statement_parse(uint32_t *block_mask, 1112 char **tokens, 1113 uint32_t n_tokens, 1114 uint32_t n_lines, 1115 uint32_t *err_line, 1116 const char **err_msg) 1117 { 1118 /* Check format. */ 1119 if ((n_tokens != 2) || strcmp(tokens[1], "{")) { 1120 if (err_line) 1121 *err_line = n_lines; 1122 if (err_msg) 1123 *err_msg = "Invalid selector statement."; 1124 return -EINVAL; 1125 } 1126 1127 /* block_mask. */ 1128 *block_mask |= 1 << SELECTOR_SELECTOR_BLOCK; 1129 1130 return 0; 1131 } 1132 1133 static int 1134 selector_selector_block_parse(struct selector_spec *s, 1135 uint32_t *block_mask, 1136 char **tokens, 1137 uint32_t n_tokens, 1138 uint32_t n_lines, 1139 uint32_t *err_line, 1140 const char **err_msg) 1141 { 1142 const char **new_fields; 1143 char *name; 1144 1145 /* Handle end of block. */ 1146 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 1147 *block_mask &= ~(1 << SELECTOR_SELECTOR_BLOCK); 1148 return 0; 1149 } 1150 1151 /* Check input arguments. */ 1152 if (n_tokens != 1) { 1153 if (err_line) 1154 *err_line = n_lines; 1155 if (err_msg) 1156 *err_msg = "Invalid selector field statement."; 1157 return -EINVAL; 1158 } 1159 1160 name = strdup(tokens[0]); 1161 if (!name) { 1162 if (err_line) 1163 *err_line = n_lines; 1164 if (err_msg) 1165 *err_msg = "Memory allocation failed."; 1166 return -ENOMEM; 1167 } 1168 1169 new_fields = realloc(s->params.selector_field_names, 1170 (s->params.n_selector_fields + 1) * sizeof(char *)); 1171 if (!new_fields) { 1172 free(name); 1173 1174 if (err_line) 1175 *err_line = n_lines; 1176 if (err_msg) 1177 *err_msg = "Memory allocation failed."; 1178 return -ENOMEM; 1179 } 1180 1181 s->params.selector_field_names = new_fields; 1182 s->params.selector_field_names[s->params.n_selector_fields] = name; 1183 s->params.n_selector_fields++; 1184 1185 return 0; 1186 } 1187 1188 static int 1189 selector_block_parse(struct selector_spec *s, 1190 uint32_t *block_mask, 1191 char **tokens, 1192 uint32_t n_tokens, 1193 uint32_t n_lines, 1194 uint32_t *err_line, 1195 const char **err_msg) 1196 { 1197 if (*block_mask & (1 << SELECTOR_SELECTOR_BLOCK)) 1198 return selector_selector_block_parse(s, 1199 block_mask, 1200 tokens, 1201 n_tokens, 1202 n_lines, 1203 err_line, 1204 err_msg); 1205 1206 /* Handle end of block. */ 1207 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 1208 *block_mask &= ~(1 << SELECTOR_BLOCK); 1209 return 0; 1210 } 1211 1212 if (!strcmp(tokens[0], "group_id")) { 1213 if (n_tokens != 2) { 1214 if (err_line) 1215 *err_line = n_lines; 1216 if (err_msg) 1217 *err_msg = "Invalid group_id statement."; 1218 return -EINVAL; 1219 } 1220 1221 s->params.group_id_field_name = strdup(tokens[1]); 1222 if (!s->params.group_id_field_name) { 1223 if (err_line) 1224 *err_line = n_lines; 1225 if (err_msg) 1226 *err_msg = "Memory allocation failed."; 1227 return -ENOMEM; 1228 } 1229 1230 return 0; 1231 } 1232 1233 if (!strcmp(tokens[0], "selector")) 1234 return selector_selector_statement_parse(block_mask, 1235 tokens, 1236 n_tokens, 1237 n_lines, 1238 err_line, 1239 err_msg); 1240 1241 if (!strcmp(tokens[0], "member_id")) { 1242 if (n_tokens != 2) { 1243 if (err_line) 1244 *err_line = n_lines; 1245 if (err_msg) 1246 *err_msg = "Invalid member_id statement."; 1247 return -EINVAL; 1248 } 1249 1250 s->params.member_id_field_name = strdup(tokens[1]); 1251 if (!s->params.member_id_field_name) { 1252 if (err_line) 1253 *err_line = n_lines; 1254 if (err_msg) 1255 *err_msg = "Memory allocation failed."; 1256 return -ENOMEM; 1257 } 1258 1259 return 0; 1260 } 1261 1262 if (!strcmp(tokens[0], "n_groups_max")) { 1263 char *p = tokens[1]; 1264 1265 if (n_tokens != 2) { 1266 if (err_line) 1267 *err_line = n_lines; 1268 if (err_msg) 1269 *err_msg = "Invalid n_groups statement."; 1270 return -EINVAL; 1271 } 1272 1273 s->params.n_groups_max = strtoul(p, &p, 0); 1274 if (p[0]) { 1275 if (err_line) 1276 *err_line = n_lines; 1277 if (err_msg) 1278 *err_msg = "Invalid n_groups argument."; 1279 return -EINVAL; 1280 } 1281 1282 return 0; 1283 } 1284 1285 if (!strcmp(tokens[0], "n_members_per_group_max")) { 1286 char *p = tokens[1]; 1287 1288 if (n_tokens != 2) { 1289 if (err_line) 1290 *err_line = n_lines; 1291 if (err_msg) 1292 *err_msg = "Invalid n_members_per_group statement."; 1293 return -EINVAL; 1294 } 1295 1296 s->params.n_members_per_group_max = strtoul(p, &p, 0); 1297 if (p[0]) { 1298 if (err_line) 1299 *err_line = n_lines; 1300 if (err_msg) 1301 *err_msg = "Invalid n_members_per_group argument."; 1302 return -EINVAL; 1303 } 1304 1305 return 0; 1306 } 1307 1308 /* Anything else. */ 1309 if (err_line) 1310 *err_line = n_lines; 1311 if (err_msg) 1312 *err_msg = "Invalid statement."; 1313 return -EINVAL; 1314 } 1315 1316 /* 1317 * learner. 1318 * 1319 * learner { 1320 * key { 1321 * MATCH_FIELD_NAME 1322 * ... 1323 * } 1324 * actions { 1325 * ACTION_NAME [ @tableonly | @defaultonly] 1326 * ... 1327 * } 1328 * default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ] 1329 * size SIZE 1330 * timeout TIMEOUT_IN_SECONDS 1331 * } 1332 */ 1333 struct learner_spec { 1334 char *name; 1335 struct rte_swx_pipeline_learner_params params; 1336 uint32_t size; 1337 uint32_t timeout; 1338 }; 1339 1340 static void 1341 learner_spec_free(struct learner_spec *s) 1342 { 1343 uintptr_t default_action_name; 1344 uint32_t i; 1345 1346 if (!s) 1347 return; 1348 1349 free(s->name); 1350 s->name = NULL; 1351 1352 for (i = 0; i < s->params.n_fields; i++) { 1353 uintptr_t name = (uintptr_t)s->params.field_names[i]; 1354 1355 free((void *)name); 1356 } 1357 1358 free(s->params.field_names); 1359 s->params.field_names = NULL; 1360 1361 s->params.n_fields = 0; 1362 1363 for (i = 0; i < s->params.n_actions; i++) { 1364 uintptr_t name = (uintptr_t)s->params.action_names[i]; 1365 1366 free((void *)name); 1367 } 1368 1369 free(s->params.action_names); 1370 s->params.action_names = NULL; 1371 1372 s->params.n_actions = 0; 1373 1374 default_action_name = (uintptr_t)s->params.default_action_name; 1375 free((void *)default_action_name); 1376 s->params.default_action_name = NULL; 1377 1378 free(s->params.default_action_data); 1379 s->params.default_action_data = NULL; 1380 1381 free(s->params.action_is_for_table_entries); 1382 s->params.action_is_for_table_entries = NULL; 1383 1384 free(s->params.action_is_for_default_entry); 1385 s->params.action_is_for_default_entry = NULL; 1386 1387 s->params.default_action_is_const = 0; 1388 1389 s->size = 0; 1390 1391 s->timeout = 0; 1392 } 1393 1394 static int 1395 learner_key_statement_parse(uint32_t *block_mask, 1396 char **tokens, 1397 uint32_t n_tokens, 1398 uint32_t n_lines, 1399 uint32_t *err_line, 1400 const char **err_msg) 1401 { 1402 /* Check format. */ 1403 if ((n_tokens != 2) || strcmp(tokens[1], "{")) { 1404 if (err_line) 1405 *err_line = n_lines; 1406 if (err_msg) 1407 *err_msg = "Invalid key statement."; 1408 return -EINVAL; 1409 } 1410 1411 /* block_mask. */ 1412 *block_mask |= 1 << LEARNER_KEY_BLOCK; 1413 1414 return 0; 1415 } 1416 1417 static int 1418 learner_key_block_parse(struct learner_spec *s, 1419 uint32_t *block_mask, 1420 char **tokens, 1421 uint32_t n_tokens, 1422 uint32_t n_lines, 1423 uint32_t *err_line, 1424 const char **err_msg) 1425 { 1426 const char **new_field_names = NULL; 1427 char *field_name = NULL; 1428 1429 /* Handle end of block. */ 1430 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 1431 *block_mask &= ~(1 << LEARNER_KEY_BLOCK); 1432 return 0; 1433 } 1434 1435 /* Check input arguments. */ 1436 if (n_tokens != 1) { 1437 if (err_line) 1438 *err_line = n_lines; 1439 if (err_msg) 1440 *err_msg = "Invalid match field statement."; 1441 return -EINVAL; 1442 } 1443 1444 field_name = strdup(tokens[0]); 1445 new_field_names = realloc(s->params.field_names, (s->params.n_fields + 1) * sizeof(char *)); 1446 if (!field_name || !new_field_names) { 1447 free(field_name); 1448 free(new_field_names); 1449 1450 if (err_line) 1451 *err_line = n_lines; 1452 if (err_msg) 1453 *err_msg = "Memory allocation failed."; 1454 return -ENOMEM; 1455 } 1456 1457 s->params.field_names = new_field_names; 1458 s->params.field_names[s->params.n_fields] = field_name; 1459 s->params.n_fields++; 1460 1461 return 0; 1462 } 1463 1464 static int 1465 learner_actions_statement_parse(uint32_t *block_mask, 1466 char **tokens, 1467 uint32_t n_tokens, 1468 uint32_t n_lines, 1469 uint32_t *err_line, 1470 const char **err_msg) 1471 { 1472 /* Check format. */ 1473 if ((n_tokens != 2) || strcmp(tokens[1], "{")) { 1474 if (err_line) 1475 *err_line = n_lines; 1476 if (err_msg) 1477 *err_msg = "Invalid actions statement."; 1478 return -EINVAL; 1479 } 1480 1481 /* block_mask. */ 1482 *block_mask |= 1 << LEARNER_ACTIONS_BLOCK; 1483 1484 return 0; 1485 } 1486 1487 static int 1488 learner_actions_block_parse(struct learner_spec *s, 1489 uint32_t *block_mask, 1490 char **tokens, 1491 uint32_t n_tokens, 1492 uint32_t n_lines, 1493 uint32_t *err_line, 1494 const char **err_msg) 1495 { 1496 const char **new_action_names = NULL; 1497 int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL; 1498 char *name = NULL; 1499 int action_is_for_table_entries = 1, action_is_for_default_entry = 1; 1500 1501 /* Handle end of block. */ 1502 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 1503 *block_mask &= ~(1 << LEARNER_ACTIONS_BLOCK); 1504 return 0; 1505 } 1506 1507 /* Check input arguments. */ 1508 if ((n_tokens > 2) || 1509 ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") && 1510 strcmp(tokens[1], "@defaultonly"))) { 1511 if (err_line) 1512 *err_line = n_lines; 1513 if (err_msg) 1514 *err_msg = "Invalid action name statement."; 1515 return -EINVAL; 1516 } 1517 1518 name = strdup(tokens[0]); 1519 1520 if (n_tokens == 2) { 1521 if (!strcmp(tokens[1], "@tableonly")) 1522 action_is_for_default_entry = 0; 1523 1524 if (!strcmp(tokens[1], "@defaultonly")) 1525 action_is_for_table_entries = 0; 1526 } 1527 1528 new_action_names = realloc(s->params.action_names, 1529 (s->params.n_actions + 1) * sizeof(char *)); 1530 new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries, 1531 (s->params.n_actions + 1) * sizeof(int)); 1532 new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry, 1533 (s->params.n_actions + 1) * sizeof(int)); 1534 1535 if (!name || 1536 !new_action_names || 1537 !new_action_is_for_table_entries || 1538 !new_action_is_for_default_entry) { 1539 free(name); 1540 free(new_action_names); 1541 free(new_action_is_for_table_entries); 1542 free(new_action_is_for_default_entry); 1543 1544 if (err_line) 1545 *err_line = n_lines; 1546 if (err_msg) 1547 *err_msg = "Memory allocation failed."; 1548 return -ENOMEM; 1549 } 1550 1551 s->params.action_names = new_action_names; 1552 s->params.action_names[s->params.n_actions] = name; 1553 1554 s->params.action_is_for_table_entries = new_action_is_for_table_entries; 1555 s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries; 1556 1557 s->params.action_is_for_default_entry = new_action_is_for_default_entry; 1558 s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry; 1559 1560 s->params.n_actions++; 1561 1562 return 0; 1563 } 1564 1565 static int 1566 learner_statement_parse(struct learner_spec *s, 1567 uint32_t *block_mask, 1568 char **tokens, 1569 uint32_t n_tokens, 1570 uint32_t n_lines, 1571 uint32_t *err_line, 1572 const char **err_msg) 1573 { 1574 /* Check format. */ 1575 if ((n_tokens != 3) || strcmp(tokens[2], "{")) { 1576 if (err_line) 1577 *err_line = n_lines; 1578 if (err_msg) 1579 *err_msg = "Invalid learner statement."; 1580 return -EINVAL; 1581 } 1582 1583 /* spec. */ 1584 s->name = strdup(tokens[1]); 1585 if (!s->name) { 1586 if (err_line) 1587 *err_line = n_lines; 1588 if (err_msg) 1589 *err_msg = "Memory allocation failed."; 1590 return -ENOMEM; 1591 } 1592 1593 /* block_mask. */ 1594 *block_mask |= 1 << LEARNER_BLOCK; 1595 1596 return 0; 1597 } 1598 1599 static int 1600 learner_block_parse(struct learner_spec *s, 1601 uint32_t *block_mask, 1602 char **tokens, 1603 uint32_t n_tokens, 1604 uint32_t n_lines, 1605 uint32_t *err_line, 1606 const char **err_msg) 1607 { 1608 if (*block_mask & (1 << LEARNER_KEY_BLOCK)) 1609 return learner_key_block_parse(s, 1610 block_mask, 1611 tokens, 1612 n_tokens, 1613 n_lines, 1614 err_line, 1615 err_msg); 1616 1617 if (*block_mask & (1 << LEARNER_ACTIONS_BLOCK)) 1618 return learner_actions_block_parse(s, 1619 block_mask, 1620 tokens, 1621 n_tokens, 1622 n_lines, 1623 err_line, 1624 err_msg); 1625 1626 /* Handle end of block. */ 1627 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 1628 *block_mask &= ~(1 << LEARNER_BLOCK); 1629 return 0; 1630 } 1631 1632 if (!strcmp(tokens[0], "key")) 1633 return learner_key_statement_parse(block_mask, 1634 tokens, 1635 n_tokens, 1636 n_lines, 1637 err_line, 1638 err_msg); 1639 1640 if (!strcmp(tokens[0], "actions")) 1641 return learner_actions_statement_parse(block_mask, 1642 tokens, 1643 n_tokens, 1644 n_lines, 1645 err_line, 1646 err_msg); 1647 1648 if (!strcmp(tokens[0], "default_action")) { 1649 if (((n_tokens != 4) && (n_tokens != 5)) || 1650 strcmp(tokens[2], "args") || 1651 strcmp(tokens[3], "none") || 1652 ((n_tokens == 5) && strcmp(tokens[4], "const"))) { 1653 if (err_line) 1654 *err_line = n_lines; 1655 if (err_msg) 1656 *err_msg = "Invalid default_action statement."; 1657 return -EINVAL; 1658 } 1659 1660 if (s->params.default_action_name) { 1661 if (err_line) 1662 *err_line = n_lines; 1663 if (err_msg) 1664 *err_msg = "Duplicate default_action stmt."; 1665 return -EINVAL; 1666 } 1667 1668 s->params.default_action_name = strdup(tokens[1]); 1669 if (!s->params.default_action_name) { 1670 if (err_line) 1671 *err_line = n_lines; 1672 if (err_msg) 1673 *err_msg = "Memory allocation failed."; 1674 return -ENOMEM; 1675 } 1676 1677 if (n_tokens == 5) 1678 s->params.default_action_is_const = 1; 1679 1680 return 0; 1681 } 1682 1683 if (!strcmp(tokens[0], "size")) { 1684 char *p = tokens[1]; 1685 1686 if (n_tokens != 2) { 1687 if (err_line) 1688 *err_line = n_lines; 1689 if (err_msg) 1690 *err_msg = "Invalid size statement."; 1691 return -EINVAL; 1692 } 1693 1694 s->size = strtoul(p, &p, 0); 1695 if (p[0]) { 1696 if (err_line) 1697 *err_line = n_lines; 1698 if (err_msg) 1699 *err_msg = "Invalid size argument."; 1700 return -EINVAL; 1701 } 1702 1703 return 0; 1704 } 1705 1706 if (!strcmp(tokens[0], "timeout")) { 1707 char *p = tokens[1]; 1708 1709 if (n_tokens != 2) { 1710 if (err_line) 1711 *err_line = n_lines; 1712 if (err_msg) 1713 *err_msg = "Invalid timeout statement."; 1714 return -EINVAL; 1715 } 1716 1717 s->timeout = strtoul(p, &p, 0); 1718 if (p[0]) { 1719 if (err_line) 1720 *err_line = n_lines; 1721 if (err_msg) 1722 *err_msg = "Invalid timeout argument."; 1723 return -EINVAL; 1724 } 1725 1726 return 0; 1727 } 1728 1729 /* Anything else. */ 1730 if (err_line) 1731 *err_line = n_lines; 1732 if (err_msg) 1733 *err_msg = "Invalid statement."; 1734 return -EINVAL; 1735 } 1736 1737 /* 1738 * regarray. 1739 * 1740 * regarray NAME size SIZE initval INITVAL 1741 */ 1742 struct regarray_spec { 1743 char *name; 1744 uint64_t init_val; 1745 uint32_t size; 1746 }; 1747 1748 static void 1749 regarray_spec_free(struct regarray_spec *s) 1750 { 1751 if (!s) 1752 return; 1753 1754 free(s->name); 1755 s->name = NULL; 1756 } 1757 1758 static int 1759 regarray_statement_parse(struct regarray_spec *s, 1760 char **tokens, 1761 uint32_t n_tokens, 1762 uint32_t n_lines, 1763 uint32_t *err_line, 1764 const char **err_msg) 1765 { 1766 char *p; 1767 1768 /* Check format. */ 1769 if ((n_tokens != 6) || 1770 strcmp(tokens[2], "size") || 1771 strcmp(tokens[4], "initval")) { 1772 if (err_line) 1773 *err_line = n_lines; 1774 if (err_msg) 1775 *err_msg = "Invalid regarray statement."; 1776 return -EINVAL; 1777 } 1778 1779 /* spec. */ 1780 s->name = strdup(tokens[1]); 1781 if (!s->name) { 1782 if (err_line) 1783 *err_line = n_lines; 1784 if (err_msg) 1785 *err_msg = "Memory allocation failed."; 1786 return -ENOMEM; 1787 } 1788 1789 p = tokens[3]; 1790 s->size = strtoul(p, &p, 0); 1791 if (p[0] || !s->size) { 1792 if (err_line) 1793 *err_line = n_lines; 1794 if (err_msg) 1795 *err_msg = "Invalid size argument."; 1796 return -EINVAL; 1797 } 1798 1799 p = tokens[5]; 1800 s->init_val = strtoull(p, &p, 0); 1801 if (p[0]) { 1802 if (err_line) 1803 *err_line = n_lines; 1804 if (err_msg) 1805 *err_msg = "Invalid initval argument."; 1806 return -EINVAL; 1807 } 1808 1809 return 0; 1810 } 1811 1812 /* 1813 * metarray. 1814 * 1815 * metarray NAME size SIZE 1816 */ 1817 struct metarray_spec { 1818 char *name; 1819 uint32_t size; 1820 }; 1821 1822 static void 1823 metarray_spec_free(struct metarray_spec *s) 1824 { 1825 if (!s) 1826 return; 1827 1828 free(s->name); 1829 s->name = NULL; 1830 } 1831 1832 static int 1833 metarray_statement_parse(struct metarray_spec *s, 1834 char **tokens, 1835 uint32_t n_tokens, 1836 uint32_t n_lines, 1837 uint32_t *err_line, 1838 const char **err_msg) 1839 { 1840 char *p; 1841 1842 /* Check format. */ 1843 if ((n_tokens != 4) || strcmp(tokens[2], "size")) { 1844 if (err_line) 1845 *err_line = n_lines; 1846 if (err_msg) 1847 *err_msg = "Invalid metarray statement."; 1848 return -EINVAL; 1849 } 1850 1851 /* spec. */ 1852 s->name = strdup(tokens[1]); 1853 if (!s->name) { 1854 if (err_line) 1855 *err_line = n_lines; 1856 if (err_msg) 1857 *err_msg = "Memory allocation failed."; 1858 return -ENOMEM; 1859 } 1860 1861 p = tokens[3]; 1862 s->size = strtoul(p, &p, 0); 1863 if (p[0] || !s->size) { 1864 if (err_line) 1865 *err_line = n_lines; 1866 if (err_msg) 1867 *err_msg = "Invalid size argument."; 1868 return -EINVAL; 1869 } 1870 1871 return 0; 1872 } 1873 1874 /* 1875 * apply. 1876 * 1877 * apply { 1878 * INSTRUCTION 1879 * ... 1880 * } 1881 */ 1882 struct apply_spec { 1883 const char **instructions; 1884 uint32_t n_instructions; 1885 }; 1886 1887 static void 1888 apply_spec_free(struct apply_spec *s) 1889 { 1890 uint32_t i; 1891 1892 if (!s) 1893 return; 1894 1895 for (i = 0; i < s->n_instructions; i++) { 1896 uintptr_t instr = (uintptr_t)s->instructions[i]; 1897 1898 free((void *)instr); 1899 } 1900 1901 free(s->instructions); 1902 s->instructions = NULL; 1903 1904 s->n_instructions = 0; 1905 } 1906 1907 static int 1908 apply_statement_parse(uint32_t *block_mask, 1909 char **tokens, 1910 uint32_t n_tokens, 1911 uint32_t n_lines, 1912 uint32_t *err_line, 1913 const char **err_msg) 1914 { 1915 /* Check format. */ 1916 if ((n_tokens != 2) || strcmp(tokens[1], "{")) { 1917 if (err_line) 1918 *err_line = n_lines; 1919 if (err_msg) 1920 *err_msg = "Invalid apply statement."; 1921 return -EINVAL; 1922 } 1923 1924 /* block_mask. */ 1925 *block_mask |= 1 << APPLY_BLOCK; 1926 1927 return 0; 1928 } 1929 1930 static int 1931 apply_block_parse(struct apply_spec *s, 1932 uint32_t *block_mask, 1933 char **tokens, 1934 uint32_t n_tokens, 1935 uint32_t n_lines, 1936 uint32_t *err_line, 1937 const char **err_msg) 1938 { 1939 char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr; 1940 const char **new_instructions; 1941 uint32_t i; 1942 1943 /* Handle end of block. */ 1944 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { 1945 *block_mask &= ~(1 << APPLY_BLOCK); 1946 return 0; 1947 } 1948 1949 /* spec. */ 1950 buffer[0] = 0; 1951 for (i = 0; i < n_tokens; i++) { 1952 if (i) 1953 strcat(buffer, " "); 1954 strcat(buffer, tokens[i]); 1955 } 1956 1957 instr = strdup(buffer); 1958 if (!instr) { 1959 if (err_line) 1960 *err_line = n_lines; 1961 if (err_msg) 1962 *err_msg = "Memory allocation failed."; 1963 return -ENOMEM; 1964 } 1965 1966 new_instructions = realloc(s->instructions, 1967 (s->n_instructions + 1) * sizeof(char *)); 1968 if (!new_instructions) { 1969 free(instr); 1970 1971 if (err_line) 1972 *err_line = n_lines; 1973 if (err_msg) 1974 *err_msg = "Memory allocation failed."; 1975 return -ENOMEM; 1976 } 1977 1978 s->instructions = new_instructions; 1979 s->instructions[s->n_instructions] = instr; 1980 s->n_instructions++; 1981 1982 return 0; 1983 } 1984 1985 /* 1986 * Pipeline. 1987 */ 1988 int 1989 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p, 1990 FILE *spec, 1991 uint32_t *err_line, 1992 const char **err_msg) 1993 { 1994 struct extobj_spec extobj_spec = {0}; 1995 struct struct_spec struct_spec = {0}; 1996 struct header_spec header_spec = {0}; 1997 struct metadata_spec metadata_spec = {0}; 1998 struct action_spec action_spec = {0}; 1999 struct table_spec table_spec = {0}; 2000 struct selector_spec selector_spec = {0}; 2001 struct learner_spec learner_spec = {0}; 2002 struct regarray_spec regarray_spec = {0}; 2003 struct metarray_spec metarray_spec = {0}; 2004 struct apply_spec apply_spec = {0}; 2005 uint32_t n_lines; 2006 uint32_t block_mask = 0; 2007 int status; 2008 2009 /* Check the input arguments. */ 2010 if (!p) { 2011 if (err_line) 2012 *err_line = 0; 2013 if (err_msg) 2014 *err_msg = "Null pipeline arument."; 2015 status = -EINVAL; 2016 goto error; 2017 } 2018 2019 if (!spec) { 2020 if (err_line) 2021 *err_line = 0; 2022 if (err_msg) 2023 *err_msg = "Null specification file argument."; 2024 status = -EINVAL; 2025 goto error; 2026 } 2027 2028 for (n_lines = 1; ; n_lines++) { 2029 char line[MAX_LINE_LENGTH]; 2030 char *tokens[MAX_TOKENS], *ptr = line; 2031 uint32_t n_tokens = 0; 2032 2033 /* Read next line. */ 2034 if (!fgets(line, sizeof(line), spec)) 2035 break; 2036 2037 /* Parse the line into tokens. */ 2038 for ( ; ; ) { 2039 char *token; 2040 2041 /* Get token. */ 2042 token = strtok_r(ptr, " \f\n\r\t\v", &ptr); 2043 if (!token) 2044 break; 2045 2046 /* Handle comments. */ 2047 if ((token[0] == '#') || 2048 (token[0] == ';') || 2049 ((token[0] == '/') && (token[1] == '/'))) { 2050 break; 2051 } 2052 2053 /* Handle excessively long lines. */ 2054 if (n_tokens >= MAX_TOKENS) { 2055 if (err_line) 2056 *err_line = n_lines; 2057 if (err_msg) 2058 *err_msg = "Too many tokens."; 2059 status = -EINVAL; 2060 goto error; 2061 } 2062 2063 /* Handle excessively long tokens. */ 2064 if (strnlen(token, RTE_SWX_NAME_SIZE) >= 2065 RTE_SWX_NAME_SIZE) { 2066 if (err_line) 2067 *err_line = n_lines; 2068 if (err_msg) 2069 *err_msg = "Token too big."; 2070 status = -EINVAL; 2071 goto error; 2072 } 2073 2074 /* Save token. */ 2075 tokens[n_tokens] = token; 2076 n_tokens++; 2077 } 2078 2079 /* Handle empty lines. */ 2080 if (!n_tokens) 2081 continue; 2082 2083 /* struct block. */ 2084 if (block_mask & (1 << STRUCT_BLOCK)) { 2085 status = struct_block_parse(&struct_spec, 2086 &block_mask, 2087 tokens, 2088 n_tokens, 2089 n_lines, 2090 err_line, 2091 err_msg); 2092 if (status) 2093 goto error; 2094 2095 if (block_mask & (1 << STRUCT_BLOCK)) 2096 continue; 2097 2098 /* End of block. */ 2099 status = rte_swx_pipeline_struct_type_register(p, 2100 struct_spec.name, 2101 struct_spec.fields, 2102 struct_spec.n_fields, 2103 struct_spec.varbit); 2104 if (status) { 2105 if (err_line) 2106 *err_line = n_lines; 2107 if (err_msg) 2108 *err_msg = "Struct registration error."; 2109 goto error; 2110 } 2111 2112 struct_spec_free(&struct_spec); 2113 2114 continue; 2115 } 2116 2117 /* action block. */ 2118 if (block_mask & (1 << ACTION_BLOCK)) { 2119 status = action_block_parse(&action_spec, 2120 &block_mask, 2121 tokens, 2122 n_tokens, 2123 n_lines, 2124 err_line, 2125 err_msg); 2126 if (status) 2127 goto error; 2128 2129 if (block_mask & (1 << ACTION_BLOCK)) 2130 continue; 2131 2132 /* End of block. */ 2133 status = rte_swx_pipeline_action_config(p, 2134 action_spec.name, 2135 action_spec.args_struct_type_name, 2136 action_spec.instructions, 2137 action_spec.n_instructions); 2138 if (status) { 2139 if (err_line) 2140 *err_line = n_lines; 2141 if (err_msg) 2142 *err_msg = "Action config error."; 2143 goto error; 2144 } 2145 2146 action_spec_free(&action_spec); 2147 2148 continue; 2149 } 2150 2151 /* table block. */ 2152 if (block_mask & (1 << TABLE_BLOCK)) { 2153 status = table_block_parse(&table_spec, 2154 &block_mask, 2155 tokens, 2156 n_tokens, 2157 n_lines, 2158 err_line, 2159 err_msg); 2160 if (status) 2161 goto error; 2162 2163 if (block_mask & (1 << TABLE_BLOCK)) 2164 continue; 2165 2166 /* End of block. */ 2167 status = rte_swx_pipeline_table_config(p, 2168 table_spec.name, 2169 &table_spec.params, 2170 table_spec.recommended_table_type_name, 2171 table_spec.args, 2172 table_spec.size); 2173 if (status) { 2174 if (err_line) 2175 *err_line = n_lines; 2176 if (err_msg) 2177 *err_msg = "Table configuration error."; 2178 goto error; 2179 } 2180 2181 table_spec_free(&table_spec); 2182 2183 continue; 2184 } 2185 2186 /* selector block. */ 2187 if (block_mask & (1 << SELECTOR_BLOCK)) { 2188 status = selector_block_parse(&selector_spec, 2189 &block_mask, 2190 tokens, 2191 n_tokens, 2192 n_lines, 2193 err_line, 2194 err_msg); 2195 if (status) 2196 goto error; 2197 2198 if (block_mask & (1 << SELECTOR_BLOCK)) 2199 continue; 2200 2201 /* End of block. */ 2202 status = rte_swx_pipeline_selector_config(p, 2203 selector_spec.name, 2204 &selector_spec.params); 2205 if (status) { 2206 if (err_line) 2207 *err_line = n_lines; 2208 if (err_msg) 2209 *err_msg = "Selector configuration error."; 2210 goto error; 2211 } 2212 2213 selector_spec_free(&selector_spec); 2214 2215 continue; 2216 } 2217 2218 /* learner block. */ 2219 if (block_mask & (1 << LEARNER_BLOCK)) { 2220 status = learner_block_parse(&learner_spec, 2221 &block_mask, 2222 tokens, 2223 n_tokens, 2224 n_lines, 2225 err_line, 2226 err_msg); 2227 if (status) 2228 goto error; 2229 2230 if (block_mask & (1 << LEARNER_BLOCK)) 2231 continue; 2232 2233 /* End of block. */ 2234 status = rte_swx_pipeline_learner_config(p, 2235 learner_spec.name, 2236 &learner_spec.params, 2237 learner_spec.size, 2238 learner_spec.timeout); 2239 if (status) { 2240 if (err_line) 2241 *err_line = n_lines; 2242 if (err_msg) 2243 *err_msg = "Learner table configuration error."; 2244 goto error; 2245 } 2246 2247 learner_spec_free(&learner_spec); 2248 2249 continue; 2250 } 2251 2252 /* apply block. */ 2253 if (block_mask & (1 << APPLY_BLOCK)) { 2254 status = apply_block_parse(&apply_spec, 2255 &block_mask, 2256 tokens, 2257 n_tokens, 2258 n_lines, 2259 err_line, 2260 err_msg); 2261 if (status) 2262 goto error; 2263 2264 if (block_mask & (1 << APPLY_BLOCK)) 2265 continue; 2266 2267 /* End of block. */ 2268 status = rte_swx_pipeline_instructions_config(p, 2269 apply_spec.instructions, 2270 apply_spec.n_instructions); 2271 if (status) { 2272 if (err_line) 2273 *err_line = n_lines; 2274 if (err_msg) 2275 *err_msg = "Pipeline instructions err."; 2276 goto error; 2277 } 2278 2279 apply_spec_free(&apply_spec); 2280 2281 continue; 2282 } 2283 2284 /* extobj. */ 2285 if (!strcmp(tokens[0], "extobj")) { 2286 status = extobj_statement_parse(&extobj_spec, 2287 tokens, 2288 n_tokens, 2289 n_lines, 2290 err_line, 2291 err_msg); 2292 if (status) 2293 goto error; 2294 2295 status = rte_swx_pipeline_extern_object_config(p, 2296 extobj_spec.name, 2297 extobj_spec.extern_type_name, 2298 extobj_spec.pragma); 2299 if (status) { 2300 if (err_line) 2301 *err_line = n_lines; 2302 if (err_msg) 2303 *err_msg = "Extern object config err."; 2304 goto error; 2305 } 2306 2307 extobj_spec_free(&extobj_spec); 2308 2309 continue; 2310 } 2311 2312 /* struct. */ 2313 if (!strcmp(tokens[0], "struct")) { 2314 status = struct_statement_parse(&struct_spec, 2315 &block_mask, 2316 tokens, 2317 n_tokens, 2318 n_lines, 2319 err_line, 2320 err_msg); 2321 if (status) 2322 goto error; 2323 2324 continue; 2325 } 2326 2327 /* header. */ 2328 if (!strcmp(tokens[0], "header")) { 2329 status = header_statement_parse(&header_spec, 2330 tokens, 2331 n_tokens, 2332 n_lines, 2333 err_line, 2334 err_msg); 2335 if (status) 2336 goto error; 2337 2338 status = rte_swx_pipeline_packet_header_register(p, 2339 header_spec.name, 2340 header_spec.struct_type_name); 2341 if (status) { 2342 if (err_line) 2343 *err_line = n_lines; 2344 if (err_msg) 2345 *err_msg = "Header registration error."; 2346 goto error; 2347 } 2348 2349 header_spec_free(&header_spec); 2350 2351 continue; 2352 } 2353 2354 /* metadata. */ 2355 if (!strcmp(tokens[0], "metadata")) { 2356 status = metadata_statement_parse(&metadata_spec, 2357 tokens, 2358 n_tokens, 2359 n_lines, 2360 err_line, 2361 err_msg); 2362 if (status) 2363 goto error; 2364 2365 status = rte_swx_pipeline_packet_metadata_register(p, 2366 metadata_spec.struct_type_name); 2367 if (status) { 2368 if (err_line) 2369 *err_line = n_lines; 2370 if (err_msg) 2371 *err_msg = "Meta-data reg err."; 2372 goto error; 2373 } 2374 2375 metadata_spec_free(&metadata_spec); 2376 2377 continue; 2378 } 2379 2380 /* action. */ 2381 if (!strcmp(tokens[0], "action")) { 2382 status = action_statement_parse(&action_spec, 2383 &block_mask, 2384 tokens, 2385 n_tokens, 2386 n_lines, 2387 err_line, 2388 err_msg); 2389 if (status) 2390 goto error; 2391 2392 continue; 2393 } 2394 2395 /* table. */ 2396 if (!strcmp(tokens[0], "table")) { 2397 status = table_statement_parse(&table_spec, 2398 &block_mask, 2399 tokens, 2400 n_tokens, 2401 n_lines, 2402 err_line, 2403 err_msg); 2404 if (status) 2405 goto error; 2406 2407 continue; 2408 } 2409 2410 /* selector. */ 2411 if (!strcmp(tokens[0], "selector")) { 2412 status = selector_statement_parse(&selector_spec, 2413 &block_mask, 2414 tokens, 2415 n_tokens, 2416 n_lines, 2417 err_line, 2418 err_msg); 2419 if (status) 2420 goto error; 2421 2422 continue; 2423 } 2424 2425 /* learner. */ 2426 if (!strcmp(tokens[0], "learner")) { 2427 status = learner_statement_parse(&learner_spec, 2428 &block_mask, 2429 tokens, 2430 n_tokens, 2431 n_lines, 2432 err_line, 2433 err_msg); 2434 if (status) 2435 goto error; 2436 2437 continue; 2438 } 2439 2440 /* regarray. */ 2441 if (!strcmp(tokens[0], "regarray")) { 2442 status = regarray_statement_parse(®array_spec, 2443 tokens, 2444 n_tokens, 2445 n_lines, 2446 err_line, 2447 err_msg); 2448 if (status) 2449 goto error; 2450 2451 status = rte_swx_pipeline_regarray_config(p, 2452 regarray_spec.name, 2453 regarray_spec.size, 2454 regarray_spec.init_val); 2455 if (status) { 2456 if (err_line) 2457 *err_line = n_lines; 2458 if (err_msg) 2459 *err_msg = "Register array configuration error."; 2460 goto error; 2461 } 2462 2463 regarray_spec_free(®array_spec); 2464 2465 continue; 2466 } 2467 2468 /* metarray. */ 2469 if (!strcmp(tokens[0], "metarray")) { 2470 status = metarray_statement_parse(&metarray_spec, 2471 tokens, 2472 n_tokens, 2473 n_lines, 2474 err_line, 2475 err_msg); 2476 if (status) 2477 goto error; 2478 2479 status = rte_swx_pipeline_metarray_config(p, 2480 metarray_spec.name, 2481 metarray_spec.size); 2482 if (status) { 2483 if (err_line) 2484 *err_line = n_lines; 2485 if (err_msg) 2486 *err_msg = "Meter array configuration error."; 2487 goto error; 2488 } 2489 2490 metarray_spec_free(&metarray_spec); 2491 2492 continue; 2493 } 2494 2495 /* apply. */ 2496 if (!strcmp(tokens[0], "apply")) { 2497 status = apply_statement_parse(&block_mask, 2498 tokens, 2499 n_tokens, 2500 n_lines, 2501 err_line, 2502 err_msg); 2503 if (status) 2504 goto error; 2505 2506 continue; 2507 } 2508 2509 /* Anything else. */ 2510 if (err_line) 2511 *err_line = n_lines; 2512 if (err_msg) 2513 *err_msg = "Unknown statement."; 2514 status = -EINVAL; 2515 goto error; 2516 } 2517 2518 /* Handle unfinished block. */ 2519 if (block_mask) { 2520 if (err_line) 2521 *err_line = n_lines; 2522 if (err_msg) 2523 *err_msg = "Missing }."; 2524 status = -EINVAL; 2525 goto error; 2526 } 2527 2528 /* Pipeline build. */ 2529 status = rte_swx_pipeline_build(p); 2530 if (status) { 2531 if (err_line) 2532 *err_line = n_lines; 2533 if (err_msg) 2534 *err_msg = "Pipeline build error."; 2535 goto error; 2536 } 2537 2538 return 0; 2539 2540 error: 2541 extobj_spec_free(&extobj_spec); 2542 struct_spec_free(&struct_spec); 2543 header_spec_free(&header_spec); 2544 metadata_spec_free(&metadata_spec); 2545 action_spec_free(&action_spec); 2546 table_spec_free(&table_spec); 2547 selector_spec_free(&selector_spec); 2548 learner_spec_free(&learner_spec); 2549 regarray_spec_free(®array_spec); 2550 metarray_spec_free(&metarray_spec); 2551 apply_spec_free(&apply_spec); 2552 return status; 2553 } 2554