1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation
10 #include "rte_swx_pipeline.h"
11 #include "rte_swx_ctl.h"
13 #define MAX_LINE_LENGTH 256
15 #define MAX_INSTRUCTION_LENGTH 256
17 #define STRUCT_BLOCK 0
18 #define ACTION_BLOCK 1
20 #define TABLE_KEY_BLOCK 3
21 #define TABLE_ACTIONS_BLOCK 4
27 * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
31 char *extern_type_name;
36 extobj_spec_free(struct extobj_spec *s)
39 free(s->extern_type_name);
44 extobj_statement_parse(struct extobj_spec *s,
52 if (((n_tokens != 4) && (n_tokens != 6)) ||
53 ((n_tokens == 4) && strcmp(tokens[2], "instanceof")) ||
54 ((n_tokens == 6) && (strcmp(tokens[2], "instanceof") ||
55 strcmp(tokens[4], "pragma")))) {
59 *err_msg = "Invalid extobj statement.";
64 s->name = strdup(tokens[1]);
65 s->extern_type_name = strdup(tokens[3]);
66 s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL;
69 !s->extern_type_name ||
70 ((n_tokens == 6) && !s->pragma)) {
72 free(s->extern_type_name);
78 *err_msg = "Memory allocation failed.";
88 * struct STRUCT_TYPE_NAME {
89 * bit<SIZE> FIELD_NAME
95 struct rte_swx_field_params *fields;
100 struct_spec_free(struct struct_spec *s)
110 for (i = 0; i < s->n_fields; i++) {
111 uintptr_t name = (uintptr_t)s->fields[i].name;
123 struct_statement_parse(struct struct_spec *s,
124 uint32_t *block_mask,
129 const char **err_msg)
132 if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
136 *err_msg = "Invalid struct statement.";
141 s->name = strdup(tokens[1]);
146 *err_msg = "Memory allocation failed.";
151 *block_mask |= 1 << STRUCT_BLOCK;
157 struct_block_parse(struct struct_spec *s,
158 uint32_t *block_mask,
163 const char **err_msg)
165 struct rte_swx_field_params *new_fields;
166 char *p = tokens[0], *name;
169 /* Handle end of block. */
170 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
171 *block_mask &= ~(1 << STRUCT_BLOCK);
176 if ((n_tokens != 2) ||
182 (p[strlen(p) - 1] != '>')) {
186 *err_msg = "Invalid struct field statement.";
190 /* Remove the "bit<" and ">". */
191 p[strlen(p) - 1] = 0;
194 n_bits = strtoul(p, &p, 0);
202 *err_msg = "Invalid struct field size.";
207 name = strdup(tokens[1]);
212 *err_msg = "Memory allocation failed.";
216 new_fields = realloc(s->fields,
217 (s->n_fields + 1) * sizeof(struct rte_swx_field_params));
224 *err_msg = "Memory allocation failed.";
228 s->fields = new_fields;
229 s->fields[s->n_fields].name = name;
230 s->fields[s->n_fields].n_bits = n_bits;
239 * header HEADER_NAME instanceof STRUCT_TYPE_NAME
243 char *struct_type_name;
247 header_spec_free(struct header_spec *s)
250 free(s->struct_type_name);
254 header_statement_parse(struct header_spec *s,
259 const char **err_msg)
262 if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) {
266 *err_msg = "Invalid header statement.";
271 s->name = strdup(tokens[1]);
272 s->struct_type_name = strdup(tokens[3]);
274 if (!s->name || !s->struct_type_name) {
276 free(s->struct_type_name);
281 *err_msg = "Memory allocation failed.";
291 * metadata instanceof STRUCT_TYPE_NAME
293 struct metadata_spec {
294 char *struct_type_name;
298 metadata_spec_free(struct metadata_spec *s)
300 free(s->struct_type_name);
304 metadata_statement_parse(struct metadata_spec *s,
309 const char **err_msg)
312 if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) {
316 *err_msg = "Invalid metadata statement.";
321 s->struct_type_name = strdup(tokens[2]);
322 if (!s->struct_type_name) {
326 *err_msg = "Memory allocation failed.";
336 * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
343 char *args_struct_type_name;
344 const char **instructions;
345 uint32_t n_instructions;
349 action_spec_free(struct action_spec *s)
359 free(s->args_struct_type_name);
360 s->args_struct_type_name = NULL;
362 for (i = 0; i < s->n_instructions; i++) {
363 uintptr_t instr = (uintptr_t)s->instructions[i];
368 free(s->instructions);
369 s->instructions = NULL;
371 s->n_instructions = 0;
375 action_statement_parse(struct action_spec *s,
376 uint32_t *block_mask,
381 const char **err_msg)
384 if (((n_tokens != 5) && (n_tokens != 6)) ||
386 (strcmp(tokens[2], "args") ||
387 strcmp(tokens[3], "none") ||
388 strcmp(tokens[4], "{"))) ||
390 (strcmp(tokens[2], "args") ||
391 strcmp(tokens[3], "instanceof") ||
392 strcmp(tokens[5], "{")))) {
396 *err_msg = "Invalid action statement.";
401 s->name = strdup(tokens[1]);
402 s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL;
404 if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) {
408 *err_msg = "Memory allocation failed.";
413 *block_mask |= 1 << ACTION_BLOCK;
419 action_block_parse(struct action_spec *s,
420 uint32_t *block_mask,
425 const char **err_msg)
427 char buffer[MAX_INSTRUCTION_LENGTH], *instr;
428 const char **new_instructions;
431 /* Handle end of block. */
432 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
433 *block_mask &= ~(1 << ACTION_BLOCK);
439 for (i = 0; i < n_tokens; i++) {
442 strcat(buffer, tokens[i]);
445 instr = strdup(buffer);
450 *err_msg = "Memory allocation failed.";
454 new_instructions = realloc(s->instructions,
455 (s->n_instructions + 1) * sizeof(char *));
456 if (!new_instructions) {
462 *err_msg = "Memory allocation failed.";
466 s->instructions = new_instructions;
467 s->instructions[s->n_instructions] = instr;
478 * MATCH_FIELD_NAME exact | wildcard | lpm
485 * default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
486 * instanceof TABLE_TYPE_NAME
493 struct rte_swx_pipeline_table_params params;
494 char *recommended_table_type_name;
500 table_spec_free(struct table_spec *s)
502 uintptr_t default_action_name;
511 for (i = 0; i < s->params.n_fields; i++) {
512 uintptr_t name = (uintptr_t)s->params.fields[i].name;
517 free(s->params.fields);
518 s->params.fields = NULL;
520 s->params.n_fields = 0;
522 for (i = 0; i < s->params.n_actions; i++) {
523 uintptr_t name = (uintptr_t)s->params.action_names[i];
528 free(s->params.action_names);
529 s->params.action_names = NULL;
531 s->params.n_actions = 0;
533 default_action_name = (uintptr_t)s->params.default_action_name;
534 free((void *)default_action_name);
535 s->params.default_action_name = NULL;
537 free(s->params.default_action_data);
538 s->params.default_action_data = NULL;
540 s->params.default_action_is_const = 0;
542 free(s->recommended_table_type_name);
543 s->recommended_table_type_name = NULL;
552 table_key_statement_parse(uint32_t *block_mask,
557 const char **err_msg)
560 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
564 *err_msg = "Invalid key statement.";
569 *block_mask |= 1 << TABLE_KEY_BLOCK;
575 table_key_block_parse(struct table_spec *s,
576 uint32_t *block_mask,
581 const char **err_msg)
583 struct rte_swx_match_field_params *new_fields;
584 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
587 /* Handle end of block. */
588 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
589 *block_mask &= ~(1 << TABLE_KEY_BLOCK);
593 /* Check input arguments. */
594 if ((n_tokens != 2) ||
595 (strcmp(tokens[1], "exact") &&
596 strcmp(tokens[1], "wildcard") &&
597 strcmp(tokens[1], "lpm"))) {
601 *err_msg = "Invalid match field statement.";
605 if (!strcmp(tokens[1], "wildcard"))
606 match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
607 if (!strcmp(tokens[1], "lpm"))
608 match_type = RTE_SWX_TABLE_MATCH_LPM;
609 if (!strcmp(tokens[1], "exact"))
610 match_type = RTE_SWX_TABLE_MATCH_EXACT;
612 name = strdup(tokens[0]);
617 *err_msg = "Memory allocation failed.";
621 new_fields = realloc(s->params.fields,
622 (s->params.n_fields + 1) * sizeof(struct rte_swx_match_field_params));
629 *err_msg = "Memory allocation failed.";
633 s->params.fields = new_fields;
634 s->params.fields[s->params.n_fields].name = name;
635 s->params.fields[s->params.n_fields].match_type = match_type;
636 s->params.n_fields++;
642 table_actions_statement_parse(uint32_t *block_mask,
647 const char **err_msg)
650 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
654 *err_msg = "Invalid actions statement.";
659 *block_mask |= 1 << TABLE_ACTIONS_BLOCK;
665 table_actions_block_parse(struct table_spec *s,
666 uint32_t *block_mask,
671 const char **err_msg)
673 const char **new_action_names;
676 /* Handle end of block. */
677 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
678 *block_mask &= ~(1 << TABLE_ACTIONS_BLOCK);
682 /* Check input arguments. */
687 *err_msg = "Invalid action name statement.";
691 name = strdup(tokens[0]);
696 *err_msg = "Memory allocation failed.";
700 new_action_names = realloc(s->params.action_names,
701 (s->params.n_actions + 1) * sizeof(char *));
702 if (!new_action_names) {
708 *err_msg = "Memory allocation failed.";
712 s->params.action_names = new_action_names;
713 s->params.action_names[s->params.n_actions] = name;
714 s->params.n_actions++;
720 table_statement_parse(struct table_spec *s,
721 uint32_t *block_mask,
726 const char **err_msg)
729 if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
733 *err_msg = "Invalid table statement.";
738 s->name = strdup(tokens[1]);
743 *err_msg = "Memory allocation failed.";
748 *block_mask |= 1 << TABLE_BLOCK;
754 table_block_parse(struct table_spec *s,
755 uint32_t *block_mask,
760 const char **err_msg)
762 if (*block_mask & (1 << TABLE_KEY_BLOCK))
763 return table_key_block_parse(s,
771 if (*block_mask & (1 << TABLE_ACTIONS_BLOCK))
772 return table_actions_block_parse(s,
780 /* Handle end of block. */
781 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
782 *block_mask &= ~(1 << TABLE_BLOCK);
786 if (!strcmp(tokens[0], "key"))
787 return table_key_statement_parse(block_mask,
794 if (!strcmp(tokens[0], "actions"))
795 return table_actions_statement_parse(block_mask,
802 if (!strcmp(tokens[0], "default_action")) {
803 if (((n_tokens != 4) && (n_tokens != 5)) ||
804 strcmp(tokens[2], "args") ||
805 strcmp(tokens[3], "none") ||
806 ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
810 *err_msg = "Invalid default_action statement.";
814 if (s->params.default_action_name) {
818 *err_msg = "Duplicate default_action stmt.";
822 s->params.default_action_name = strdup(tokens[1]);
823 if (!s->params.default_action_name) {
827 *err_msg = "Memory allocation failed.";
832 s->params.default_action_is_const = 1;
837 if (!strcmp(tokens[0], "instanceof")) {
842 *err_msg = "Invalid instanceof statement.";
846 if (s->recommended_table_type_name) {
850 *err_msg = "Duplicate instanceof statement.";
854 s->recommended_table_type_name = strdup(tokens[1]);
855 if (!s->recommended_table_type_name) {
859 *err_msg = "Memory allocation failed.";
866 if (!strcmp(tokens[0], "pragma")) {
871 *err_msg = "Invalid pragma statement.";
879 *err_msg = "Duplicate pragma statement.";
883 s->args = strdup(tokens[1]);
888 *err_msg = "Memory allocation failed.";
895 if (!strcmp(tokens[0], "size")) {
902 *err_msg = "Invalid pragma statement.";
906 s->size = strtoul(p, &p, 0);
911 *err_msg = "Invalid size argument.";
922 *err_msg = "Invalid statement.";
935 const char **instructions;
936 uint32_t n_instructions;
940 apply_spec_free(struct apply_spec *s)
947 for (i = 0; i < s->n_instructions; i++) {
948 uintptr_t instr = (uintptr_t)s->instructions[i];
953 free(s->instructions);
954 s->instructions = NULL;
956 s->n_instructions = 0;
960 apply_statement_parse(uint32_t *block_mask,
965 const char **err_msg)
968 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
972 *err_msg = "Invalid apply statement.";
977 *block_mask |= 1 << APPLY_BLOCK;
983 apply_block_parse(struct apply_spec *s,
984 uint32_t *block_mask,
989 const char **err_msg)
991 char buffer[MAX_INSTRUCTION_LENGTH], *instr;
992 const char **new_instructions;
995 /* Handle end of block. */
996 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
997 *block_mask &= ~(1 << APPLY_BLOCK);
1003 for (i = 0; i < n_tokens; i++) {
1005 strcat(buffer, " ");
1006 strcat(buffer, tokens[i]);
1009 instr = strdup(buffer);
1012 *err_line = n_lines;
1014 *err_msg = "Memory allocation failed.";
1018 new_instructions = realloc(s->instructions,
1019 (s->n_instructions + 1) * sizeof(char *));
1020 if (!new_instructions) {
1024 *err_line = n_lines;
1026 *err_msg = "Memory allocation failed.";
1030 s->instructions = new_instructions;
1031 s->instructions[s->n_instructions] = instr;
1032 s->n_instructions++;
1041 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1044 const char **err_msg)
1046 struct extobj_spec extobj_spec = {0};
1047 struct struct_spec struct_spec = {0};
1048 struct header_spec header_spec = {0};
1049 struct metadata_spec metadata_spec = {0};
1050 struct action_spec action_spec = {0};
1051 struct table_spec table_spec = {0};
1052 struct apply_spec apply_spec = {0};
1054 uint32_t block_mask = 0;
1057 /* Check the input arguments. */
1062 *err_msg = "Null pipeline arument.";
1071 *err_msg = "Null specification file argument.";
1076 for (n_lines = 1; ; n_lines++) {
1077 char line[MAX_LINE_LENGTH];
1078 char *tokens[MAX_TOKENS], *ptr = line;
1079 uint32_t n_tokens = 0;
1081 /* Read next line. */
1082 if (!fgets(line, sizeof(line), spec))
1085 /* Parse the line into tokens. */
1090 token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
1094 /* Handle comments. */
1095 if ((token[0] == '#') ||
1096 (token[0] == ';') ||
1097 ((token[0] == '/') && (token[1] == '/'))) {
1101 /* Handle excessively long lines. */
1102 if (n_tokens >= MAX_TOKENS) {
1104 *err_line = n_lines;
1106 *err_msg = "Too many tokens.";
1112 tokens[n_tokens] = token;
1116 /* Handle empty lines. */
1121 if (block_mask & (1 << STRUCT_BLOCK)) {
1122 status = struct_block_parse(&struct_spec,
1132 if (block_mask & (1 << STRUCT_BLOCK))
1136 status = rte_swx_pipeline_struct_type_register(p,
1139 struct_spec.n_fields);
1142 *err_line = n_lines;
1144 *err_msg = "Struct registration error.";
1148 struct_spec_free(&struct_spec);
1154 if (block_mask & (1 << ACTION_BLOCK)) {
1155 status = action_block_parse(&action_spec,
1165 if (block_mask & (1 << ACTION_BLOCK))
1169 status = rte_swx_pipeline_action_config(p,
1171 action_spec.args_struct_type_name,
1172 action_spec.instructions,
1173 action_spec.n_instructions);
1176 *err_line = n_lines;
1178 *err_msg = "Action config error.";
1182 action_spec_free(&action_spec);
1188 if (block_mask & (1 << TABLE_BLOCK)) {
1189 status = table_block_parse(&table_spec,
1199 if (block_mask & (1 << TABLE_BLOCK))
1203 status = rte_swx_pipeline_table_config(p,
1206 table_spec.recommended_table_type_name,
1211 *err_line = n_lines;
1213 *err_msg = "Table configuration error.";
1217 table_spec_free(&table_spec);
1223 if (block_mask & (1 << APPLY_BLOCK)) {
1224 status = apply_block_parse(&apply_spec,
1234 if (block_mask & (1 << APPLY_BLOCK))
1238 status = rte_swx_pipeline_instructions_config(p,
1239 apply_spec.instructions,
1240 apply_spec.n_instructions);
1243 *err_line = n_lines;
1245 *err_msg = "Pipeline instructions err.";
1249 apply_spec_free(&apply_spec);
1255 if (!strcmp(tokens[0], "extobj")) {
1256 status = extobj_statement_parse(&extobj_spec,
1265 status = rte_swx_pipeline_extern_object_config(p,
1267 extobj_spec.extern_type_name,
1268 extobj_spec.pragma);
1271 *err_line = n_lines;
1273 *err_msg = "Extern object config err.";
1277 extobj_spec_free(&extobj_spec);
1283 if (!strcmp(tokens[0], "struct")) {
1284 status = struct_statement_parse(&struct_spec,
1298 if (!strcmp(tokens[0], "header")) {
1299 status = header_statement_parse(&header_spec,
1308 status = rte_swx_pipeline_packet_header_register(p,
1310 header_spec.struct_type_name);
1313 *err_line = n_lines;
1315 *err_msg = "Header registration error.";
1319 header_spec_free(&header_spec);
1325 if (!strcmp(tokens[0], "metadata")) {
1326 status = metadata_statement_parse(&metadata_spec,
1335 status = rte_swx_pipeline_packet_metadata_register(p,
1336 metadata_spec.struct_type_name);
1339 *err_line = n_lines;
1341 *err_msg = "Meta-data reg err.";
1345 metadata_spec_free(&metadata_spec);
1351 if (!strcmp(tokens[0], "action")) {
1352 status = action_statement_parse(&action_spec,
1366 if (!strcmp(tokens[0], "table")) {
1367 status = table_statement_parse(&table_spec,
1381 if (!strcmp(tokens[0], "apply")) {
1382 status = apply_statement_parse(&block_mask,
1394 /* Anything else. */
1396 *err_line = n_lines;
1398 *err_msg = "Unknown statement.";
1403 /* Handle unfinished block. */
1406 *err_line = n_lines;
1408 *err_msg = "Missing }.";
1413 /* Pipeline build. */
1414 status = rte_swx_pipeline_build(p);
1417 *err_line = n_lines;
1419 *err_msg = "Pipeline build error.";
1426 extobj_spec_free(&extobj_spec);
1427 struct_spec_free(&struct_spec);
1428 header_spec_free(&header_spec);
1429 metadata_spec_free(&metadata_spec);
1430 action_spec_free(&action_spec);
1431 table_spec_free(&table_spec);
1432 apply_spec_free(&apply_spec);