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