1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation
10 #include <rte_common.h>
12 #include "rte_swx_pipeline.h"
14 #ifndef MAX_LINE_LENGTH
15 #define MAX_LINE_LENGTH 2048
19 #define MAX_TOKENS 256
22 #define STRUCT_BLOCK 0
23 #define ACTION_BLOCK 1
25 #define TABLE_KEY_BLOCK 3
26 #define TABLE_ACTIONS_BLOCK 4
27 #define SELECTOR_BLOCK 5
28 #define SELECTOR_SELECTOR_BLOCK 6
29 #define LEARNER_BLOCK 7
30 #define LEARNER_KEY_BLOCK 8
31 #define LEARNER_ACTIONS_BLOCK 9
32 #define LEARNER_TIMEOUT_BLOCK 10
33 #define APPLY_BLOCK 11
38 * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
42 char *extern_type_name;
47 extobj_spec_free(struct extobj_spec *s)
55 free(s->extern_type_name);
56 s->extern_type_name = NULL;
63 extobj_statement_parse(struct extobj_spec *s,
71 if (((n_tokens != 4) && (n_tokens != 6)) ||
72 ((n_tokens == 4) && strcmp(tokens[2], "instanceof")) ||
73 ((n_tokens == 6) && (strcmp(tokens[2], "instanceof") ||
74 strcmp(tokens[4], "pragma")))) {
78 *err_msg = "Invalid extobj statement.";
83 s->name = strdup(tokens[1]);
84 s->extern_type_name = strdup(tokens[3]);
85 s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL;
88 !s->extern_type_name ||
89 ((n_tokens == 6) && !s->pragma)) {
91 free(s->extern_type_name);
97 *err_msg = "Memory allocation failed.";
107 * struct STRUCT_TYPE_NAME {
108 * bit<SIZE> | varbit<SIZE> FIELD_NAME
114 struct rte_swx_field_params *fields;
120 struct_spec_free(struct struct_spec *s)
130 for (i = 0; i < s->n_fields; i++) {
131 uintptr_t name = (uintptr_t)s->fields[i].name;
145 struct_statement_parse(struct struct_spec *s,
146 uint32_t *block_mask,
151 const char **err_msg)
154 if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
158 *err_msg = "Invalid struct statement.";
163 s->name = strdup(tokens[1]);
168 *err_msg = "Memory allocation failed.";
173 *block_mask |= 1 << STRUCT_BLOCK;
179 struct_block_parse(struct struct_spec *s,
180 uint32_t *block_mask,
185 const char **err_msg)
187 struct rte_swx_field_params *new_fields;
188 char *p = tokens[0], *name = NULL;
190 int varbit = 0, error = 0, error_size_invalid = 0, error_varbit_not_last = 0;
192 /* Handle end of block. */
193 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
194 *block_mask &= ~(1 << STRUCT_BLOCK);
206 error_varbit_not_last = 1;
210 if (!strncmp(p, "bit<", strlen("bit<"))) {
211 size_t len = strlen(p);
213 if ((len < strlen("bit< >")) || (p[len - 1] != '>')) {
218 /* Remove the "bit<" and ">". */
219 p[strlen(p) - 1] = 0;
221 } else if (!strncmp(p, "varbit<", strlen("varbit<"))) {
222 size_t len = strlen(p);
224 if ((len < strlen("varbit< >")) || (p[len - 1] != '>')) {
229 /* Remove the "varbit<" and ">". */
230 p[strlen(p) - 1] = 0;
231 p += strlen("varbit<");
233 /* Set the varbit flag. */
240 n_bits = strtoul(p, &p, 0);
244 ((n_bits > 64) && !varbit)) {
246 error_size_invalid = 1;
251 name = strdup(tokens[1]);
257 new_fields = realloc(s->fields, (s->n_fields + 1) * sizeof(struct rte_swx_field_params));
263 s->fields = new_fields;
264 s->fields[s->n_fields].name = name;
265 s->fields[s->n_fields].n_bits = n_bits;
278 *err_msg = "Invalid struct field statement.";
280 if ((error == -EINVAL) && error_varbit_not_last)
281 *err_msg = "Varbit field is not the last struct field.";
283 if ((error == -EINVAL) && error_size_invalid)
284 *err_msg = "Invalid struct field size.";
286 if (error == -ENOMEM)
287 *err_msg = "Memory allocation failed.";
296 * header HEADER_NAME instanceof STRUCT_TYPE_NAME
300 char *struct_type_name;
304 header_spec_free(struct header_spec *s)
312 free(s->struct_type_name);
313 s->struct_type_name = NULL;
317 header_statement_parse(struct header_spec *s,
322 const char **err_msg)
325 if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) {
329 *err_msg = "Invalid header statement.";
334 s->name = strdup(tokens[1]);
335 s->struct_type_name = strdup(tokens[3]);
337 if (!s->name || !s->struct_type_name) {
339 free(s->struct_type_name);
344 *err_msg = "Memory allocation failed.";
354 * metadata instanceof STRUCT_TYPE_NAME
356 struct metadata_spec {
357 char *struct_type_name;
361 metadata_spec_free(struct metadata_spec *s)
366 free(s->struct_type_name);
367 s->struct_type_name = NULL;
371 metadata_statement_parse(struct metadata_spec *s,
376 const char **err_msg)
379 if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) {
383 *err_msg = "Invalid metadata statement.";
388 s->struct_type_name = strdup(tokens[2]);
389 if (!s->struct_type_name) {
393 *err_msg = "Memory allocation failed.";
403 * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
410 char *args_struct_type_name;
411 const char **instructions;
412 uint32_t n_instructions;
416 action_spec_free(struct action_spec *s)
426 free(s->args_struct_type_name);
427 s->args_struct_type_name = NULL;
429 for (i = 0; i < s->n_instructions; i++) {
430 uintptr_t instr = (uintptr_t)s->instructions[i];
435 free(s->instructions);
436 s->instructions = NULL;
438 s->n_instructions = 0;
442 action_statement_parse(struct action_spec *s,
443 uint32_t *block_mask,
448 const char **err_msg)
451 if (((n_tokens != 5) && (n_tokens != 6)) ||
453 (strcmp(tokens[2], "args") ||
454 strcmp(tokens[3], "none") ||
455 strcmp(tokens[4], "{"))) ||
457 (strcmp(tokens[2], "args") ||
458 strcmp(tokens[3], "instanceof") ||
459 strcmp(tokens[5], "{")))) {
463 *err_msg = "Invalid action statement.";
468 s->name = strdup(tokens[1]);
469 s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL;
471 if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) {
475 *err_msg = "Memory allocation failed.";
480 *block_mask |= 1 << ACTION_BLOCK;
486 action_block_parse(struct action_spec *s,
487 uint32_t *block_mask,
492 const char **err_msg)
494 char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
495 const char **new_instructions;
498 /* Handle end of block. */
499 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
500 *block_mask &= ~(1 << ACTION_BLOCK);
506 for (i = 0; i < n_tokens; i++) {
509 strcat(buffer, tokens[i]);
512 instr = strdup(buffer);
517 *err_msg = "Memory allocation failed.";
521 new_instructions = realloc(s->instructions,
522 (s->n_instructions + 1) * sizeof(char *));
523 if (!new_instructions) {
529 *err_msg = "Memory allocation failed.";
533 s->instructions = new_instructions;
534 s->instructions[s->n_instructions] = instr;
545 * MATCH_FIELD_NAME exact | wildcard | lpm
549 * ACTION_NAME [ @tableonly | @defaultonly ]
552 * default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
553 * instanceof TABLE_TYPE_NAME
560 struct rte_swx_pipeline_table_params params;
561 char *recommended_table_type_name;
567 table_spec_free(struct table_spec *s)
569 uintptr_t default_action_name, default_action_args;
578 for (i = 0; i < s->params.n_fields; i++) {
579 uintptr_t name = (uintptr_t)s->params.fields[i].name;
584 free(s->params.fields);
585 s->params.fields = NULL;
587 s->params.n_fields = 0;
589 for (i = 0; i < s->params.n_actions; i++) {
590 uintptr_t name = (uintptr_t)s->params.action_names[i];
595 free(s->params.action_names);
596 s->params.action_names = NULL;
598 s->params.n_actions = 0;
600 default_action_name = (uintptr_t)s->params.default_action_name;
601 free((void *)default_action_name);
602 s->params.default_action_name = NULL;
604 default_action_args = (uintptr_t)s->params.default_action_args;
605 free((void *)default_action_args);
606 s->params.default_action_args = NULL;
608 free(s->params.action_is_for_table_entries);
609 s->params.action_is_for_table_entries = NULL;
611 free(s->params.action_is_for_default_entry);
612 s->params.action_is_for_default_entry = NULL;
614 s->params.default_action_is_const = 0;
616 free(s->recommended_table_type_name);
617 s->recommended_table_type_name = NULL;
626 table_key_statement_parse(uint32_t *block_mask,
631 const char **err_msg)
634 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
638 *err_msg = "Invalid key statement.";
643 *block_mask |= 1 << TABLE_KEY_BLOCK;
649 table_key_block_parse(struct table_spec *s,
650 uint32_t *block_mask,
655 const char **err_msg)
657 struct rte_swx_match_field_params *new_fields;
658 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
661 /* Handle end of block. */
662 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
663 *block_mask &= ~(1 << TABLE_KEY_BLOCK);
667 /* Check input arguments. */
668 if ((n_tokens != 2) ||
669 (strcmp(tokens[1], "exact") &&
670 strcmp(tokens[1], "wildcard") &&
671 strcmp(tokens[1], "lpm"))) {
675 *err_msg = "Invalid match field statement.";
679 if (!strcmp(tokens[1], "wildcard"))
680 match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
681 if (!strcmp(tokens[1], "lpm"))
682 match_type = RTE_SWX_TABLE_MATCH_LPM;
683 if (!strcmp(tokens[1], "exact"))
684 match_type = RTE_SWX_TABLE_MATCH_EXACT;
686 name = strdup(tokens[0]);
691 *err_msg = "Memory allocation failed.";
695 new_fields = realloc(s->params.fields,
696 (s->params.n_fields + 1) * sizeof(struct rte_swx_match_field_params));
703 *err_msg = "Memory allocation failed.";
707 s->params.fields = new_fields;
708 s->params.fields[s->params.n_fields].name = name;
709 s->params.fields[s->params.n_fields].match_type = match_type;
710 s->params.n_fields++;
716 table_actions_statement_parse(uint32_t *block_mask,
721 const char **err_msg)
724 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
728 *err_msg = "Invalid actions statement.";
733 *block_mask |= 1 << TABLE_ACTIONS_BLOCK;
739 table_actions_block_parse(struct table_spec *s,
740 uint32_t *block_mask,
745 const char **err_msg)
747 const char **new_action_names = NULL;
748 int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
750 int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
752 /* Handle end of block. */
753 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
754 *block_mask &= ~(1 << TABLE_ACTIONS_BLOCK);
758 /* Check input arguments. */
759 if ((n_tokens > 2) ||
760 ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
761 strcmp(tokens[1], "@defaultonly"))) {
765 *err_msg = "Invalid action name statement.";
769 name = strdup(tokens[0]);
772 if (!strcmp(tokens[1], "@tableonly"))
773 action_is_for_default_entry = 0;
775 if (!strcmp(tokens[1], "@defaultonly"))
776 action_is_for_table_entries = 0;
779 new_action_names = realloc(s->params.action_names,
780 (s->params.n_actions + 1) * sizeof(char *));
781 new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
782 (s->params.n_actions + 1) * sizeof(int));
783 new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
784 (s->params.n_actions + 1) * sizeof(int));
788 !new_action_is_for_table_entries ||
789 !new_action_is_for_default_entry) {
791 free(new_action_names);
792 free(new_action_is_for_table_entries);
793 free(new_action_is_for_default_entry);
798 *err_msg = "Memory allocation failed.";
802 s->params.action_names = new_action_names;
803 s->params.action_names[s->params.n_actions] = name;
805 s->params.action_is_for_table_entries = new_action_is_for_table_entries;
806 s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
808 s->params.action_is_for_default_entry = new_action_is_for_default_entry;
809 s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
811 s->params.n_actions++;
817 table_default_action_statement_parse(struct table_spec *s,
822 const char **err_msg)
825 int status = 0, duplicate = 0;
828 if ((n_tokens < 4) ||
829 strcmp(tokens[2], "args")) {
834 if (s->params.default_action_name) {
840 s->params.default_action_name = strdup(tokens[1]);
841 if (!s->params.default_action_name) {
846 if (strcmp(tokens[3], "none")) {
847 char buffer[MAX_LINE_LENGTH];
848 uint32_t n_tokens_args = n_tokens - 3;
850 if (!strcmp(tokens[n_tokens - 1], "const"))
853 if (!n_tokens_args) {
859 for (i = 0; i < n_tokens_args; i++) {
863 strcat(buffer, tokens[3 + i]);
866 s->params.default_action_args = strdup(buffer);
867 if (!s->params.default_action_args) {
872 if (((n_tokens != 4) && (n_tokens != 5)) ||
873 ((n_tokens == 5) && (strcmp(tokens[4], "const")))) {
879 if (!strcmp(tokens[n_tokens - 1], "const"))
880 s->params.default_action_is_const = 1;
891 *err_msg = "Memory allocation failed.";
896 *err_msg = "Duplicate default_action statement.";
898 *err_msg = "Invalid default_action statement.";
905 table_statement_parse(struct table_spec *s,
906 uint32_t *block_mask,
911 const char **err_msg)
914 if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
918 *err_msg = "Invalid table statement.";
923 s->name = strdup(tokens[1]);
928 *err_msg = "Memory allocation failed.";
933 *block_mask |= 1 << TABLE_BLOCK;
939 table_block_parse(struct table_spec *s,
940 uint32_t *block_mask,
945 const char **err_msg)
947 if (*block_mask & (1 << TABLE_KEY_BLOCK))
948 return table_key_block_parse(s,
956 if (*block_mask & (1 << TABLE_ACTIONS_BLOCK))
957 return table_actions_block_parse(s,
965 /* Handle end of block. */
966 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
967 *block_mask &= ~(1 << TABLE_BLOCK);
971 if (!strcmp(tokens[0], "key"))
972 return table_key_statement_parse(block_mask,
979 if (!strcmp(tokens[0], "actions"))
980 return table_actions_statement_parse(block_mask,
987 if (!strcmp(tokens[0], "default_action"))
988 return table_default_action_statement_parse(s,
995 if (!strcmp(tokens[0], "instanceof")) {
1000 *err_msg = "Invalid instanceof statement.";
1004 if (s->recommended_table_type_name) {
1006 *err_line = n_lines;
1008 *err_msg = "Duplicate instanceof statement.";
1012 s->recommended_table_type_name = strdup(tokens[1]);
1013 if (!s->recommended_table_type_name) {
1015 *err_line = n_lines;
1017 *err_msg = "Memory allocation failed.";
1024 if (!strcmp(tokens[0], "pragma")) {
1025 if (n_tokens != 2) {
1027 *err_line = n_lines;
1029 *err_msg = "Invalid pragma statement.";
1035 *err_line = n_lines;
1037 *err_msg = "Duplicate pragma statement.";
1041 s->args = strdup(tokens[1]);
1044 *err_line = n_lines;
1046 *err_msg = "Memory allocation failed.";
1053 if (!strcmp(tokens[0], "size")) {
1054 char *p = tokens[1];
1056 if (n_tokens != 2) {
1058 *err_line = n_lines;
1060 *err_msg = "Invalid pragma statement.";
1064 s->size = strtoul(p, &p, 0);
1067 *err_line = n_lines;
1069 *err_msg = "Invalid size argument.";
1076 /* Anything else. */
1078 *err_line = n_lines;
1080 *err_msg = "Invalid statement.";
1087 * selector SELECTOR_NAME {
1088 * group_id FIELD_NAME
1093 * member_id FIELD_NAME
1095 * n_members_per_group N_MEMBERS_PER_GROUP
1098 struct selector_spec {
1100 struct rte_swx_pipeline_selector_params params;
1104 selector_spec_free(struct selector_spec *s)
1106 uintptr_t field_name;
1116 /* params->group_id_field_name. */
1117 field_name = (uintptr_t)s->params.group_id_field_name;
1118 free((void *)field_name);
1119 s->params.group_id_field_name = NULL;
1121 /* params->selector_field_names. */
1122 for (i = 0; i < s->params.n_selector_fields; i++) {
1123 field_name = (uintptr_t)s->params.selector_field_names[i];
1125 free((void *)field_name);
1128 free(s->params.selector_field_names);
1129 s->params.selector_field_names = NULL;
1131 s->params.n_selector_fields = 0;
1133 /* params->member_id_field_name. */
1134 field_name = (uintptr_t)s->params.member_id_field_name;
1135 free((void *)field_name);
1136 s->params.member_id_field_name = NULL;
1138 /* params->n_groups_max. */
1139 s->params.n_groups_max = 0;
1141 /* params->n_members_per_group_max. */
1142 s->params.n_members_per_group_max = 0;
1146 selector_statement_parse(struct selector_spec *s,
1147 uint32_t *block_mask,
1152 const char **err_msg)
1155 if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
1157 *err_line = n_lines;
1159 *err_msg = "Invalid selector statement.";
1164 s->name = strdup(tokens[1]);
1167 *err_line = n_lines;
1169 *err_msg = "Memory allocation failed.";
1174 *block_mask |= 1 << SELECTOR_BLOCK;
1180 selector_selector_statement_parse(uint32_t *block_mask,
1185 const char **err_msg)
1188 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1190 *err_line = n_lines;
1192 *err_msg = "Invalid selector statement.";
1197 *block_mask |= 1 << SELECTOR_SELECTOR_BLOCK;
1203 selector_selector_block_parse(struct selector_spec *s,
1204 uint32_t *block_mask,
1209 const char **err_msg)
1211 const char **new_fields;
1214 /* Handle end of block. */
1215 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1216 *block_mask &= ~(1 << SELECTOR_SELECTOR_BLOCK);
1220 /* Check input arguments. */
1221 if (n_tokens != 1) {
1223 *err_line = n_lines;
1225 *err_msg = "Invalid selector field statement.";
1229 name = strdup(tokens[0]);
1232 *err_line = n_lines;
1234 *err_msg = "Memory allocation failed.";
1238 new_fields = realloc(s->params.selector_field_names,
1239 (s->params.n_selector_fields + 1) * sizeof(char *));
1244 *err_line = n_lines;
1246 *err_msg = "Memory allocation failed.";
1250 s->params.selector_field_names = new_fields;
1251 s->params.selector_field_names[s->params.n_selector_fields] = name;
1252 s->params.n_selector_fields++;
1258 selector_block_parse(struct selector_spec *s,
1259 uint32_t *block_mask,
1264 const char **err_msg)
1266 if (*block_mask & (1 << SELECTOR_SELECTOR_BLOCK))
1267 return selector_selector_block_parse(s,
1275 /* Handle end of block. */
1276 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1277 *block_mask &= ~(1 << SELECTOR_BLOCK);
1281 if (!strcmp(tokens[0], "group_id")) {
1282 if (n_tokens != 2) {
1284 *err_line = n_lines;
1286 *err_msg = "Invalid group_id statement.";
1290 s->params.group_id_field_name = strdup(tokens[1]);
1291 if (!s->params.group_id_field_name) {
1293 *err_line = n_lines;
1295 *err_msg = "Memory allocation failed.";
1302 if (!strcmp(tokens[0], "selector"))
1303 return selector_selector_statement_parse(block_mask,
1310 if (!strcmp(tokens[0], "member_id")) {
1311 if (n_tokens != 2) {
1313 *err_line = n_lines;
1315 *err_msg = "Invalid member_id statement.";
1319 s->params.member_id_field_name = strdup(tokens[1]);
1320 if (!s->params.member_id_field_name) {
1322 *err_line = n_lines;
1324 *err_msg = "Memory allocation failed.";
1331 if (!strcmp(tokens[0], "n_groups_max")) {
1332 char *p = tokens[1];
1334 if (n_tokens != 2) {
1336 *err_line = n_lines;
1338 *err_msg = "Invalid n_groups statement.";
1342 s->params.n_groups_max = strtoul(p, &p, 0);
1345 *err_line = n_lines;
1347 *err_msg = "Invalid n_groups argument.";
1354 if (!strcmp(tokens[0], "n_members_per_group_max")) {
1355 char *p = tokens[1];
1357 if (n_tokens != 2) {
1359 *err_line = n_lines;
1361 *err_msg = "Invalid n_members_per_group statement.";
1365 s->params.n_members_per_group_max = strtoul(p, &p, 0);
1368 *err_line = n_lines;
1370 *err_msg = "Invalid n_members_per_group argument.";
1377 /* Anything else. */
1379 *err_line = n_lines;
1381 *err_msg = "Invalid statement.";
1388 * learner LEARNER_NAME {
1394 * ACTION_NAME [ @tableonly | @defaultonly]
1397 * default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
1400 * TIMEOUT_IN_SECONDS
1405 struct learner_spec {
1407 struct rte_swx_pipeline_learner_params params;
1410 uint32_t n_timeouts;
1414 learner_spec_free(struct learner_spec *s)
1416 uintptr_t default_action_name, default_action_args;
1425 for (i = 0; i < s->params.n_fields; i++) {
1426 uintptr_t name = (uintptr_t)s->params.field_names[i];
1431 free(s->params.field_names);
1432 s->params.field_names = NULL;
1434 s->params.n_fields = 0;
1436 for (i = 0; i < s->params.n_actions; i++) {
1437 uintptr_t name = (uintptr_t)s->params.action_names[i];
1442 free(s->params.action_names);
1443 s->params.action_names = NULL;
1445 s->params.n_actions = 0;
1447 default_action_name = (uintptr_t)s->params.default_action_name;
1448 free((void *)default_action_name);
1449 s->params.default_action_name = NULL;
1451 default_action_args = (uintptr_t)s->params.default_action_args;
1452 free((void *)default_action_args);
1453 s->params.default_action_args = NULL;
1455 free(s->params.action_is_for_table_entries);
1456 s->params.action_is_for_table_entries = NULL;
1458 free(s->params.action_is_for_default_entry);
1459 s->params.action_is_for_default_entry = NULL;
1461 s->params.default_action_is_const = 0;
1472 learner_key_statement_parse(uint32_t *block_mask,
1477 const char **err_msg)
1480 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1482 *err_line = n_lines;
1484 *err_msg = "Invalid key statement.";
1489 *block_mask |= 1 << LEARNER_KEY_BLOCK;
1495 learner_key_block_parse(struct learner_spec *s,
1496 uint32_t *block_mask,
1501 const char **err_msg)
1503 const char **new_field_names = NULL;
1504 char *field_name = NULL;
1506 /* Handle end of block. */
1507 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1508 *block_mask &= ~(1 << LEARNER_KEY_BLOCK);
1512 /* Check input arguments. */
1513 if (n_tokens != 1) {
1515 *err_line = n_lines;
1517 *err_msg = "Invalid match field statement.";
1521 field_name = strdup(tokens[0]);
1522 new_field_names = realloc(s->params.field_names, (s->params.n_fields + 1) * sizeof(char *));
1523 if (!field_name || !new_field_names) {
1525 free(new_field_names);
1528 *err_line = n_lines;
1530 *err_msg = "Memory allocation failed.";
1534 s->params.field_names = new_field_names;
1535 s->params.field_names[s->params.n_fields] = field_name;
1536 s->params.n_fields++;
1542 learner_actions_statement_parse(uint32_t *block_mask,
1547 const char **err_msg)
1550 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1552 *err_line = n_lines;
1554 *err_msg = "Invalid actions statement.";
1559 *block_mask |= 1 << LEARNER_ACTIONS_BLOCK;
1565 learner_actions_block_parse(struct learner_spec *s,
1566 uint32_t *block_mask,
1571 const char **err_msg)
1573 const char **new_action_names = NULL;
1574 int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
1576 int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
1578 /* Handle end of block. */
1579 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1580 *block_mask &= ~(1 << LEARNER_ACTIONS_BLOCK);
1584 /* Check input arguments. */
1585 if ((n_tokens > 2) ||
1586 ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
1587 strcmp(tokens[1], "@defaultonly"))) {
1589 *err_line = n_lines;
1591 *err_msg = "Invalid action name statement.";
1595 name = strdup(tokens[0]);
1597 if (n_tokens == 2) {
1598 if (!strcmp(tokens[1], "@tableonly"))
1599 action_is_for_default_entry = 0;
1601 if (!strcmp(tokens[1], "@defaultonly"))
1602 action_is_for_table_entries = 0;
1605 new_action_names = realloc(s->params.action_names,
1606 (s->params.n_actions + 1) * sizeof(char *));
1607 new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
1608 (s->params.n_actions + 1) * sizeof(int));
1609 new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
1610 (s->params.n_actions + 1) * sizeof(int));
1613 !new_action_names ||
1614 !new_action_is_for_table_entries ||
1615 !new_action_is_for_default_entry) {
1617 free(new_action_names);
1618 free(new_action_is_for_table_entries);
1619 free(new_action_is_for_default_entry);
1622 *err_line = n_lines;
1624 *err_msg = "Memory allocation failed.";
1628 s->params.action_names = new_action_names;
1629 s->params.action_names[s->params.n_actions] = name;
1631 s->params.action_is_for_table_entries = new_action_is_for_table_entries;
1632 s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
1634 s->params.action_is_for_default_entry = new_action_is_for_default_entry;
1635 s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
1637 s->params.n_actions++;
1643 learner_default_action_statement_parse(struct learner_spec *s,
1648 const char **err_msg)
1651 int status = 0, duplicate = 0;
1654 if ((n_tokens < 4) ||
1655 strcmp(tokens[2], "args")) {
1660 if (s->params.default_action_name) {
1666 s->params.default_action_name = strdup(tokens[1]);
1667 if (!s->params.default_action_name) {
1672 if (strcmp(tokens[3], "none")) {
1673 char buffer[MAX_LINE_LENGTH];
1674 uint32_t n_tokens_args = n_tokens - 3;
1676 if (!strcmp(tokens[n_tokens - 1], "const"))
1679 if (!n_tokens_args) {
1685 for (i = 0; i < n_tokens_args; i++) {
1687 strcat(buffer, " ");
1689 strcat(buffer, tokens[3 + i]);
1692 s->params.default_action_args = strdup(buffer);
1693 if (!s->params.default_action_args) {
1698 if (((n_tokens != 4) && (n_tokens != 5)) ||
1699 ((n_tokens == 5) && (strcmp(tokens[4], "const")))) {
1705 if (!strcmp(tokens[n_tokens - 1], "const"))
1706 s->params.default_action_is_const = 1;
1712 *err_line = n_lines;
1717 *err_msg = "Memory allocation failed.";
1722 *err_msg = "Duplicate default_action statement.";
1724 *err_msg = "Invalid default_action statement.";
1731 learner_timeout_statement_parse(uint32_t *block_mask,
1736 const char **err_msg)
1739 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1741 *err_line = n_lines;
1743 *err_msg = "Invalid timeout statement.";
1748 *block_mask |= 1 << LEARNER_TIMEOUT_BLOCK;
1754 learner_timeout_block_parse(struct learner_spec *s,
1755 uint32_t *block_mask,
1760 const char **err_msg)
1762 uint32_t *new_timeout = NULL;
1767 /* Handle end of block. */
1768 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1769 *block_mask &= ~(1 << LEARNER_TIMEOUT_BLOCK);
1773 /* Check input arguments. */
1774 if (n_tokens != 1) {
1780 val = strtoul(str, &str, 0);
1786 new_timeout = realloc(s->timeout, (s->n_timeouts + 1) * sizeof(uint32_t));
1792 s->timeout = new_timeout;
1793 s->timeout[s->n_timeouts] = val;
1802 *err_line = n_lines;
1807 *err_msg = "Memory allocation failed.";
1811 *err_msg = "Invalid timeout value statement.";
1820 learner_statement_parse(struct learner_spec *s,
1821 uint32_t *block_mask,
1826 const char **err_msg)
1829 if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
1831 *err_line = n_lines;
1833 *err_msg = "Invalid learner statement.";
1838 s->name = strdup(tokens[1]);
1841 *err_line = n_lines;
1843 *err_msg = "Memory allocation failed.";
1848 *block_mask |= 1 << LEARNER_BLOCK;
1854 learner_block_parse(struct learner_spec *s,
1855 uint32_t *block_mask,
1860 const char **err_msg)
1862 if (*block_mask & (1 << LEARNER_KEY_BLOCK))
1863 return learner_key_block_parse(s,
1871 if (*block_mask & (1 << LEARNER_ACTIONS_BLOCK))
1872 return learner_actions_block_parse(s,
1880 if (*block_mask & (1 << LEARNER_TIMEOUT_BLOCK))
1881 return learner_timeout_block_parse(s,
1889 /* Handle end of block. */
1890 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1891 *block_mask &= ~(1 << LEARNER_BLOCK);
1895 if (!strcmp(tokens[0], "key"))
1896 return learner_key_statement_parse(block_mask,
1903 if (!strcmp(tokens[0], "actions"))
1904 return learner_actions_statement_parse(block_mask,
1911 if (!strcmp(tokens[0], "default_action"))
1912 return learner_default_action_statement_parse(s,
1919 if (!strcmp(tokens[0], "size")) {
1920 char *p = tokens[1];
1922 if (n_tokens != 2) {
1924 *err_line = n_lines;
1926 *err_msg = "Invalid size statement.";
1930 s->size = strtoul(p, &p, 0);
1933 *err_line = n_lines;
1935 *err_msg = "Invalid size argument.";
1942 if (!strcmp(tokens[0], "timeout"))
1943 return learner_timeout_statement_parse(block_mask,
1950 /* Anything else. */
1952 *err_line = n_lines;
1954 *err_msg = "Invalid statement.";
1961 * regarray NAME size SIZE initval INITVAL
1963 struct regarray_spec {
1970 regarray_spec_free(struct regarray_spec *s)
1980 regarray_statement_parse(struct regarray_spec *s,
1985 const char **err_msg)
1990 if ((n_tokens != 6) ||
1991 strcmp(tokens[2], "size") ||
1992 strcmp(tokens[4], "initval")) {
1994 *err_line = n_lines;
1996 *err_msg = "Invalid regarray statement.";
2001 s->name = strdup(tokens[1]);
2004 *err_line = n_lines;
2006 *err_msg = "Memory allocation failed.";
2011 s->size = strtoul(p, &p, 0);
2012 if (p[0] || !s->size) {
2014 *err_line = n_lines;
2016 *err_msg = "Invalid size argument.";
2021 s->init_val = strtoull(p, &p, 0);
2024 *err_line = n_lines;
2026 *err_msg = "Invalid initval argument.";
2036 * metarray NAME size SIZE
2038 struct metarray_spec {
2044 metarray_spec_free(struct metarray_spec *s)
2054 metarray_statement_parse(struct metarray_spec *s,
2059 const char **err_msg)
2064 if ((n_tokens != 4) || strcmp(tokens[2], "size")) {
2066 *err_line = n_lines;
2068 *err_msg = "Invalid metarray statement.";
2073 s->name = strdup(tokens[1]);
2076 *err_line = n_lines;
2078 *err_msg = "Memory allocation failed.";
2083 s->size = strtoul(p, &p, 0);
2084 if (p[0] || !s->size) {
2086 *err_line = n_lines;
2088 *err_msg = "Invalid size argument.";
2104 const char **instructions;
2105 uint32_t n_instructions;
2109 apply_spec_free(struct apply_spec *s)
2116 for (i = 0; i < s->n_instructions; i++) {
2117 uintptr_t instr = (uintptr_t)s->instructions[i];
2119 free((void *)instr);
2122 free(s->instructions);
2123 s->instructions = NULL;
2125 s->n_instructions = 0;
2129 apply_statement_parse(uint32_t *block_mask,
2134 const char **err_msg)
2137 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
2139 *err_line = n_lines;
2141 *err_msg = "Invalid apply statement.";
2146 *block_mask |= 1 << APPLY_BLOCK;
2152 apply_block_parse(struct apply_spec *s,
2153 uint32_t *block_mask,
2158 const char **err_msg)
2160 char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
2161 const char **new_instructions;
2164 /* Handle end of block. */
2165 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
2166 *block_mask &= ~(1 << APPLY_BLOCK);
2172 for (i = 0; i < n_tokens; i++) {
2174 strcat(buffer, " ");
2175 strcat(buffer, tokens[i]);
2178 instr = strdup(buffer);
2181 *err_line = n_lines;
2183 *err_msg = "Memory allocation failed.";
2187 new_instructions = realloc(s->instructions,
2188 (s->n_instructions + 1) * sizeof(char *));
2189 if (!new_instructions) {
2193 *err_line = n_lines;
2195 *err_msg = "Memory allocation failed.";
2199 s->instructions = new_instructions;
2200 s->instructions[s->n_instructions] = instr;
2201 s->n_instructions++;
2210 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
2213 const char **err_msg)
2215 struct extobj_spec extobj_spec = {0};
2216 struct struct_spec struct_spec = {0};
2217 struct header_spec header_spec = {0};
2218 struct metadata_spec metadata_spec = {0};
2219 struct action_spec action_spec = {0};
2220 struct table_spec table_spec = {0};
2221 struct selector_spec selector_spec = {0};
2222 struct learner_spec learner_spec = {0};
2223 struct regarray_spec regarray_spec = {0};
2224 struct metarray_spec metarray_spec = {0};
2225 struct apply_spec apply_spec = {0};
2227 uint32_t block_mask = 0;
2230 /* Check the input arguments. */
2235 *err_msg = "Null pipeline argument.";
2244 *err_msg = "Null specification file argument.";
2249 for (n_lines = 1; ; n_lines++) {
2250 char line[MAX_LINE_LENGTH];
2251 char *tokens[MAX_TOKENS], *ptr = line;
2252 uint32_t n_tokens = 0;
2254 /* Read next line. */
2255 if (!fgets(line, sizeof(line), spec))
2258 /* Parse the line into tokens. */
2263 token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
2267 /* Handle comments. */
2268 if ((token[0] == '#') ||
2269 (token[0] == ';') ||
2270 ((token[0] == '/') && (token[1] == '/'))) {
2274 /* Handle excessively long lines. */
2275 if (n_tokens >= RTE_DIM(tokens)) {
2277 *err_line = n_lines;
2279 *err_msg = "Too many tokens.";
2284 /* Handle excessively long tokens. */
2285 if (strnlen(token, RTE_SWX_NAME_SIZE) >=
2286 RTE_SWX_NAME_SIZE) {
2288 *err_line = n_lines;
2290 *err_msg = "Token too big.";
2296 tokens[n_tokens] = token;
2300 /* Handle empty lines. */
2305 if (block_mask & (1 << STRUCT_BLOCK)) {
2306 status = struct_block_parse(&struct_spec,
2316 if (block_mask & (1 << STRUCT_BLOCK))
2320 status = rte_swx_pipeline_struct_type_register(p,
2323 struct_spec.n_fields,
2324 struct_spec.varbit);
2327 *err_line = n_lines;
2329 *err_msg = "Struct registration error.";
2333 struct_spec_free(&struct_spec);
2339 if (block_mask & (1 << ACTION_BLOCK)) {
2340 status = action_block_parse(&action_spec,
2350 if (block_mask & (1 << ACTION_BLOCK))
2354 status = rte_swx_pipeline_action_config(p,
2356 action_spec.args_struct_type_name,
2357 action_spec.instructions,
2358 action_spec.n_instructions);
2361 *err_line = n_lines;
2363 *err_msg = "Action config error.";
2367 action_spec_free(&action_spec);
2373 if (block_mask & (1 << TABLE_BLOCK)) {
2374 status = table_block_parse(&table_spec,
2384 if (block_mask & (1 << TABLE_BLOCK))
2388 status = rte_swx_pipeline_table_config(p,
2391 table_spec.recommended_table_type_name,
2396 *err_line = n_lines;
2398 *err_msg = "Table configuration error.";
2402 table_spec_free(&table_spec);
2407 /* selector block. */
2408 if (block_mask & (1 << SELECTOR_BLOCK)) {
2409 status = selector_block_parse(&selector_spec,
2419 if (block_mask & (1 << SELECTOR_BLOCK))
2423 status = rte_swx_pipeline_selector_config(p,
2425 &selector_spec.params);
2428 *err_line = n_lines;
2430 *err_msg = "Selector configuration error.";
2434 selector_spec_free(&selector_spec);
2439 /* learner block. */
2440 if (block_mask & (1 << LEARNER_BLOCK)) {
2441 status = learner_block_parse(&learner_spec,
2451 if (block_mask & (1 << LEARNER_BLOCK))
2455 status = rte_swx_pipeline_learner_config(p,
2457 &learner_spec.params,
2459 learner_spec.timeout,
2460 learner_spec.n_timeouts);
2463 *err_line = n_lines;
2465 *err_msg = "Learner table configuration error.";
2469 learner_spec_free(&learner_spec);
2475 if (block_mask & (1 << APPLY_BLOCK)) {
2476 status = apply_block_parse(&apply_spec,
2486 if (block_mask & (1 << APPLY_BLOCK))
2490 status = rte_swx_pipeline_instructions_config(p,
2491 apply_spec.instructions,
2492 apply_spec.n_instructions);
2495 *err_line = n_lines;
2497 *err_msg = "Pipeline instructions err.";
2501 apply_spec_free(&apply_spec);
2507 if (!strcmp(tokens[0], "extobj")) {
2508 status = extobj_statement_parse(&extobj_spec,
2517 status = rte_swx_pipeline_extern_object_config(p,
2519 extobj_spec.extern_type_name,
2520 extobj_spec.pragma);
2523 *err_line = n_lines;
2525 *err_msg = "Extern object config err.";
2529 extobj_spec_free(&extobj_spec);
2535 if (!strcmp(tokens[0], "struct")) {
2536 status = struct_statement_parse(&struct_spec,
2550 if (!strcmp(tokens[0], "header")) {
2551 status = header_statement_parse(&header_spec,
2560 status = rte_swx_pipeline_packet_header_register(p,
2562 header_spec.struct_type_name);
2565 *err_line = n_lines;
2567 *err_msg = "Header registration error.";
2571 header_spec_free(&header_spec);
2577 if (!strcmp(tokens[0], "metadata")) {
2578 status = metadata_statement_parse(&metadata_spec,
2587 status = rte_swx_pipeline_packet_metadata_register(p,
2588 metadata_spec.struct_type_name);
2591 *err_line = n_lines;
2593 *err_msg = "Meta-data reg err.";
2597 metadata_spec_free(&metadata_spec);
2603 if (!strcmp(tokens[0], "action")) {
2604 status = action_statement_parse(&action_spec,
2618 if (!strcmp(tokens[0], "table")) {
2619 status = table_statement_parse(&table_spec,
2633 if (!strcmp(tokens[0], "selector")) {
2634 status = selector_statement_parse(&selector_spec,
2648 if (!strcmp(tokens[0], "learner")) {
2649 status = learner_statement_parse(&learner_spec,
2663 if (!strcmp(tokens[0], "regarray")) {
2664 status = regarray_statement_parse(®array_spec,
2673 status = rte_swx_pipeline_regarray_config(p,
2676 regarray_spec.init_val);
2679 *err_line = n_lines;
2681 *err_msg = "Register array configuration error.";
2685 regarray_spec_free(®array_spec);
2691 if (!strcmp(tokens[0], "metarray")) {
2692 status = metarray_statement_parse(&metarray_spec,
2701 status = rte_swx_pipeline_metarray_config(p,
2703 metarray_spec.size);
2706 *err_line = n_lines;
2708 *err_msg = "Meter array configuration error.";
2712 metarray_spec_free(&metarray_spec);
2718 if (!strcmp(tokens[0], "apply")) {
2719 status = apply_statement_parse(&block_mask,
2731 /* Anything else. */
2733 *err_line = n_lines;
2735 *err_msg = "Unknown statement.";
2740 /* Handle unfinished block. */
2743 *err_line = n_lines;
2745 *err_msg = "Missing }.";
2750 /* Pipeline build. */
2751 status = rte_swx_pipeline_build(p);
2754 *err_line = n_lines;
2756 *err_msg = "Pipeline build error.";
2763 extobj_spec_free(&extobj_spec);
2764 struct_spec_free(&struct_spec);
2765 header_spec_free(&header_spec);
2766 metadata_spec_free(&metadata_spec);
2767 action_spec_free(&action_spec);
2768 table_spec_free(&table_spec);
2769 selector_spec_free(&selector_spec);
2770 learner_spec_free(&learner_spec);
2771 regarray_spec_free(®array_spec);
2772 metarray_spec_free(&metarray_spec);
2773 apply_spec_free(&apply_spec);