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 RTE_SWX_INSTRUCTION_SIZE
14 #define MAX_TOKENS RTE_SWX_INSTRUCTION_TOKENS_MAX
16 #define STRUCT_BLOCK 0
17 #define ACTION_BLOCK 1
19 #define TABLE_KEY_BLOCK 3
20 #define TABLE_ACTIONS_BLOCK 4
26 * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
30 char *extern_type_name;
35 extobj_spec_free(struct extobj_spec *s)
43 free(s->extern_type_name);
44 s->extern_type_name = NULL;
51 extobj_statement_parse(struct extobj_spec *s,
59 if (((n_tokens != 4) && (n_tokens != 6)) ||
60 ((n_tokens == 4) && strcmp(tokens[2], "instanceof")) ||
61 ((n_tokens == 6) && (strcmp(tokens[2], "instanceof") ||
62 strcmp(tokens[4], "pragma")))) {
66 *err_msg = "Invalid extobj statement.";
71 s->name = strdup(tokens[1]);
72 s->extern_type_name = strdup(tokens[3]);
73 s->pragma = (n_tokens == 6) ? strdup(tokens[5]) : NULL;
76 !s->extern_type_name ||
77 ((n_tokens == 6) && !s->pragma)) {
79 free(s->extern_type_name);
85 *err_msg = "Memory allocation failed.";
95 * struct STRUCT_TYPE_NAME {
96 * bit<SIZE> FIELD_NAME
102 struct rte_swx_field_params *fields;
107 struct_spec_free(struct struct_spec *s)
117 for (i = 0; i < s->n_fields; i++) {
118 uintptr_t name = (uintptr_t)s->fields[i].name;
130 struct_statement_parse(struct struct_spec *s,
131 uint32_t *block_mask,
136 const char **err_msg)
139 if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
143 *err_msg = "Invalid struct statement.";
148 s->name = strdup(tokens[1]);
153 *err_msg = "Memory allocation failed.";
158 *block_mask |= 1 << STRUCT_BLOCK;
164 struct_block_parse(struct struct_spec *s,
165 uint32_t *block_mask,
170 const char **err_msg)
172 struct rte_swx_field_params *new_fields;
173 char *p = tokens[0], *name;
176 /* Handle end of block. */
177 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
178 *block_mask &= ~(1 << STRUCT_BLOCK);
183 if ((n_tokens != 2) ||
189 (p[strlen(p) - 1] != '>')) {
193 *err_msg = "Invalid struct field statement.";
197 /* Remove the "bit<" and ">". */
198 p[strlen(p) - 1] = 0;
201 n_bits = strtoul(p, &p, 0);
209 *err_msg = "Invalid struct field size.";
214 name = strdup(tokens[1]);
219 *err_msg = "Memory allocation failed.";
223 new_fields = realloc(s->fields,
224 (s->n_fields + 1) * sizeof(struct rte_swx_field_params));
231 *err_msg = "Memory allocation failed.";
235 s->fields = new_fields;
236 s->fields[s->n_fields].name = name;
237 s->fields[s->n_fields].n_bits = n_bits;
246 * header HEADER_NAME instanceof STRUCT_TYPE_NAME
250 char *struct_type_name;
254 header_spec_free(struct header_spec *s)
262 free(s->struct_type_name);
263 s->struct_type_name = NULL;
267 header_statement_parse(struct header_spec *s,
272 const char **err_msg)
275 if ((n_tokens != 4) || strcmp(tokens[2], "instanceof")) {
279 *err_msg = "Invalid header statement.";
284 s->name = strdup(tokens[1]);
285 s->struct_type_name = strdup(tokens[3]);
287 if (!s->name || !s->struct_type_name) {
289 free(s->struct_type_name);
294 *err_msg = "Memory allocation failed.";
304 * metadata instanceof STRUCT_TYPE_NAME
306 struct metadata_spec {
307 char *struct_type_name;
311 metadata_spec_free(struct metadata_spec *s)
316 free(s->struct_type_name);
317 s->struct_type_name = NULL;
321 metadata_statement_parse(struct metadata_spec *s,
326 const char **err_msg)
329 if ((n_tokens != 3) || strcmp(tokens[1], "instanceof")) {
333 *err_msg = "Invalid metadata statement.";
338 s->struct_type_name = strdup(tokens[2]);
339 if (!s->struct_type_name) {
343 *err_msg = "Memory allocation failed.";
353 * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
360 char *args_struct_type_name;
361 const char **instructions;
362 uint32_t n_instructions;
366 action_spec_free(struct action_spec *s)
376 free(s->args_struct_type_name);
377 s->args_struct_type_name = NULL;
379 for (i = 0; i < s->n_instructions; i++) {
380 uintptr_t instr = (uintptr_t)s->instructions[i];
385 free(s->instructions);
386 s->instructions = NULL;
388 s->n_instructions = 0;
392 action_statement_parse(struct action_spec *s,
393 uint32_t *block_mask,
398 const char **err_msg)
401 if (((n_tokens != 5) && (n_tokens != 6)) ||
403 (strcmp(tokens[2], "args") ||
404 strcmp(tokens[3], "none") ||
405 strcmp(tokens[4], "{"))) ||
407 (strcmp(tokens[2], "args") ||
408 strcmp(tokens[3], "instanceof") ||
409 strcmp(tokens[5], "{")))) {
413 *err_msg = "Invalid action statement.";
418 s->name = strdup(tokens[1]);
419 s->args_struct_type_name = (n_tokens == 6) ? strdup(tokens[4]) : NULL;
421 if ((!s->name) || ((n_tokens == 6) && !s->args_struct_type_name)) {
425 *err_msg = "Memory allocation failed.";
430 *block_mask |= 1 << ACTION_BLOCK;
436 action_block_parse(struct action_spec *s,
437 uint32_t *block_mask,
442 const char **err_msg)
444 char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
445 const char **new_instructions;
448 /* Handle end of block. */
449 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
450 *block_mask &= ~(1 << ACTION_BLOCK);
456 for (i = 0; i < n_tokens; i++) {
459 strcat(buffer, tokens[i]);
462 instr = strdup(buffer);
467 *err_msg = "Memory allocation failed.";
471 new_instructions = realloc(s->instructions,
472 (s->n_instructions + 1) * sizeof(char *));
473 if (!new_instructions) {
479 *err_msg = "Memory allocation failed.";
483 s->instructions = new_instructions;
484 s->instructions[s->n_instructions] = instr;
495 * MATCH_FIELD_NAME exact | wildcard | lpm
502 * default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
503 * instanceof TABLE_TYPE_NAME
510 struct rte_swx_pipeline_table_params params;
511 char *recommended_table_type_name;
517 table_spec_free(struct table_spec *s)
519 uintptr_t default_action_name;
528 for (i = 0; i < s->params.n_fields; i++) {
529 uintptr_t name = (uintptr_t)s->params.fields[i].name;
534 free(s->params.fields);
535 s->params.fields = NULL;
537 s->params.n_fields = 0;
539 for (i = 0; i < s->params.n_actions; i++) {
540 uintptr_t name = (uintptr_t)s->params.action_names[i];
545 free(s->params.action_names);
546 s->params.action_names = NULL;
548 s->params.n_actions = 0;
550 default_action_name = (uintptr_t)s->params.default_action_name;
551 free((void *)default_action_name);
552 s->params.default_action_name = NULL;
554 free(s->params.default_action_data);
555 s->params.default_action_data = NULL;
557 s->params.default_action_is_const = 0;
559 free(s->recommended_table_type_name);
560 s->recommended_table_type_name = NULL;
569 table_key_statement_parse(uint32_t *block_mask,
574 const char **err_msg)
577 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
581 *err_msg = "Invalid key statement.";
586 *block_mask |= 1 << TABLE_KEY_BLOCK;
592 table_key_block_parse(struct table_spec *s,
593 uint32_t *block_mask,
598 const char **err_msg)
600 struct rte_swx_match_field_params *new_fields;
601 enum rte_swx_table_match_type match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
604 /* Handle end of block. */
605 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
606 *block_mask &= ~(1 << TABLE_KEY_BLOCK);
610 /* Check input arguments. */
611 if ((n_tokens != 2) ||
612 (strcmp(tokens[1], "exact") &&
613 strcmp(tokens[1], "wildcard") &&
614 strcmp(tokens[1], "lpm"))) {
618 *err_msg = "Invalid match field statement.";
622 if (!strcmp(tokens[1], "wildcard"))
623 match_type = RTE_SWX_TABLE_MATCH_WILDCARD;
624 if (!strcmp(tokens[1], "lpm"))
625 match_type = RTE_SWX_TABLE_MATCH_LPM;
626 if (!strcmp(tokens[1], "exact"))
627 match_type = RTE_SWX_TABLE_MATCH_EXACT;
629 name = strdup(tokens[0]);
634 *err_msg = "Memory allocation failed.";
638 new_fields = realloc(s->params.fields,
639 (s->params.n_fields + 1) * sizeof(struct rte_swx_match_field_params));
646 *err_msg = "Memory allocation failed.";
650 s->params.fields = new_fields;
651 s->params.fields[s->params.n_fields].name = name;
652 s->params.fields[s->params.n_fields].match_type = match_type;
653 s->params.n_fields++;
659 table_actions_statement_parse(uint32_t *block_mask,
664 const char **err_msg)
667 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
671 *err_msg = "Invalid actions statement.";
676 *block_mask |= 1 << TABLE_ACTIONS_BLOCK;
682 table_actions_block_parse(struct table_spec *s,
683 uint32_t *block_mask,
688 const char **err_msg)
690 const char **new_action_names;
693 /* Handle end of block. */
694 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
695 *block_mask &= ~(1 << TABLE_ACTIONS_BLOCK);
699 /* Check input arguments. */
704 *err_msg = "Invalid action name statement.";
708 name = strdup(tokens[0]);
713 *err_msg = "Memory allocation failed.";
717 new_action_names = realloc(s->params.action_names,
718 (s->params.n_actions + 1) * sizeof(char *));
719 if (!new_action_names) {
725 *err_msg = "Memory allocation failed.";
729 s->params.action_names = new_action_names;
730 s->params.action_names[s->params.n_actions] = name;
731 s->params.n_actions++;
737 table_statement_parse(struct table_spec *s,
738 uint32_t *block_mask,
743 const char **err_msg)
746 if ((n_tokens != 3) || strcmp(tokens[2], "{")) {
750 *err_msg = "Invalid table statement.";
755 s->name = strdup(tokens[1]);
760 *err_msg = "Memory allocation failed.";
765 *block_mask |= 1 << TABLE_BLOCK;
771 table_block_parse(struct table_spec *s,
772 uint32_t *block_mask,
777 const char **err_msg)
779 if (*block_mask & (1 << TABLE_KEY_BLOCK))
780 return table_key_block_parse(s,
788 if (*block_mask & (1 << TABLE_ACTIONS_BLOCK))
789 return table_actions_block_parse(s,
797 /* Handle end of block. */
798 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
799 *block_mask &= ~(1 << TABLE_BLOCK);
803 if (!strcmp(tokens[0], "key"))
804 return table_key_statement_parse(block_mask,
811 if (!strcmp(tokens[0], "actions"))
812 return table_actions_statement_parse(block_mask,
819 if (!strcmp(tokens[0], "default_action")) {
820 if (((n_tokens != 4) && (n_tokens != 5)) ||
821 strcmp(tokens[2], "args") ||
822 strcmp(tokens[3], "none") ||
823 ((n_tokens == 5) && strcmp(tokens[4], "const"))) {
827 *err_msg = "Invalid default_action statement.";
831 if (s->params.default_action_name) {
835 *err_msg = "Duplicate default_action stmt.";
839 s->params.default_action_name = strdup(tokens[1]);
840 if (!s->params.default_action_name) {
844 *err_msg = "Memory allocation failed.";
849 s->params.default_action_is_const = 1;
854 if (!strcmp(tokens[0], "instanceof")) {
859 *err_msg = "Invalid instanceof statement.";
863 if (s->recommended_table_type_name) {
867 *err_msg = "Duplicate instanceof statement.";
871 s->recommended_table_type_name = strdup(tokens[1]);
872 if (!s->recommended_table_type_name) {
876 *err_msg = "Memory allocation failed.";
883 if (!strcmp(tokens[0], "pragma")) {
888 *err_msg = "Invalid pragma statement.";
896 *err_msg = "Duplicate pragma statement.";
900 s->args = strdup(tokens[1]);
905 *err_msg = "Memory allocation failed.";
912 if (!strcmp(tokens[0], "size")) {
919 *err_msg = "Invalid pragma statement.";
923 s->size = strtoul(p, &p, 0);
928 *err_msg = "Invalid size argument.";
939 *err_msg = "Invalid statement.";
946 * regarray NAME size SIZE initval INITVAL
948 struct regarray_spec {
955 regarray_spec_free(struct regarray_spec *s)
965 regarray_statement_parse(struct regarray_spec *s,
970 const char **err_msg)
975 if ((n_tokens != 6) ||
976 strcmp(tokens[2], "size") ||
977 strcmp(tokens[4], "initval")) {
981 *err_msg = "Invalid regarray statement.";
986 s->name = strdup(tokens[1]);
991 *err_msg = "Memory allocation failed.";
996 s->size = strtoul(p, &p, 0);
997 if (p[0] || !s->size) {
1001 *err_msg = "Invalid size argument.";
1006 s->init_val = strtoull(p, &p, 0);
1009 *err_line = n_lines;
1011 *err_msg = "Invalid initval argument.";
1027 const char **instructions;
1028 uint32_t n_instructions;
1032 apply_spec_free(struct apply_spec *s)
1039 for (i = 0; i < s->n_instructions; i++) {
1040 uintptr_t instr = (uintptr_t)s->instructions[i];
1042 free((void *)instr);
1045 free(s->instructions);
1046 s->instructions = NULL;
1048 s->n_instructions = 0;
1052 apply_statement_parse(uint32_t *block_mask,
1057 const char **err_msg)
1060 if ((n_tokens != 2) || strcmp(tokens[1], "{")) {
1062 *err_line = n_lines;
1064 *err_msg = "Invalid apply statement.";
1069 *block_mask |= 1 << APPLY_BLOCK;
1075 apply_block_parse(struct apply_spec *s,
1076 uint32_t *block_mask,
1081 const char **err_msg)
1083 char buffer[RTE_SWX_INSTRUCTION_SIZE], *instr;
1084 const char **new_instructions;
1087 /* Handle end of block. */
1088 if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
1089 *block_mask &= ~(1 << APPLY_BLOCK);
1095 for (i = 0; i < n_tokens; i++) {
1097 strcat(buffer, " ");
1098 strcat(buffer, tokens[i]);
1101 instr = strdup(buffer);
1104 *err_line = n_lines;
1106 *err_msg = "Memory allocation failed.";
1110 new_instructions = realloc(s->instructions,
1111 (s->n_instructions + 1) * sizeof(char *));
1112 if (!new_instructions) {
1116 *err_line = n_lines;
1118 *err_msg = "Memory allocation failed.";
1122 s->instructions = new_instructions;
1123 s->instructions[s->n_instructions] = instr;
1124 s->n_instructions++;
1133 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
1136 const char **err_msg)
1138 struct extobj_spec extobj_spec = {0};
1139 struct struct_spec struct_spec = {0};
1140 struct header_spec header_spec = {0};
1141 struct metadata_spec metadata_spec = {0};
1142 struct action_spec action_spec = {0};
1143 struct table_spec table_spec = {0};
1144 struct regarray_spec regarray_spec = {0};
1145 struct apply_spec apply_spec = {0};
1147 uint32_t block_mask = 0;
1150 /* Check the input arguments. */
1155 *err_msg = "Null pipeline arument.";
1164 *err_msg = "Null specification file argument.";
1169 for (n_lines = 1; ; n_lines++) {
1170 char line[MAX_LINE_LENGTH];
1171 char *tokens[MAX_TOKENS], *ptr = line;
1172 uint32_t n_tokens = 0;
1174 /* Read next line. */
1175 if (!fgets(line, sizeof(line), spec))
1178 /* Parse the line into tokens. */
1183 token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
1187 /* Handle comments. */
1188 if ((token[0] == '#') ||
1189 (token[0] == ';') ||
1190 ((token[0] == '/') && (token[1] == '/'))) {
1194 /* Handle excessively long lines. */
1195 if (n_tokens >= MAX_TOKENS) {
1197 *err_line = n_lines;
1199 *err_msg = "Too many tokens.";
1204 /* Handle excessively long tokens. */
1205 if (strnlen(token, RTE_SWX_NAME_SIZE) >=
1206 RTE_SWX_NAME_SIZE) {
1208 *err_line = n_lines;
1210 *err_msg = "Token too big.";
1216 tokens[n_tokens] = token;
1220 /* Handle empty lines. */
1225 if (block_mask & (1 << STRUCT_BLOCK)) {
1226 status = struct_block_parse(&struct_spec,
1236 if (block_mask & (1 << STRUCT_BLOCK))
1240 status = rte_swx_pipeline_struct_type_register(p,
1243 struct_spec.n_fields);
1246 *err_line = n_lines;
1248 *err_msg = "Struct registration error.";
1252 struct_spec_free(&struct_spec);
1258 if (block_mask & (1 << ACTION_BLOCK)) {
1259 status = action_block_parse(&action_spec,
1269 if (block_mask & (1 << ACTION_BLOCK))
1273 status = rte_swx_pipeline_action_config(p,
1275 action_spec.args_struct_type_name,
1276 action_spec.instructions,
1277 action_spec.n_instructions);
1280 *err_line = n_lines;
1282 *err_msg = "Action config error.";
1286 action_spec_free(&action_spec);
1292 if (block_mask & (1 << TABLE_BLOCK)) {
1293 status = table_block_parse(&table_spec,
1303 if (block_mask & (1 << TABLE_BLOCK))
1307 status = rte_swx_pipeline_table_config(p,
1310 table_spec.recommended_table_type_name,
1315 *err_line = n_lines;
1317 *err_msg = "Table configuration error.";
1321 table_spec_free(&table_spec);
1327 if (block_mask & (1 << APPLY_BLOCK)) {
1328 status = apply_block_parse(&apply_spec,
1338 if (block_mask & (1 << APPLY_BLOCK))
1342 status = rte_swx_pipeline_instructions_config(p,
1343 apply_spec.instructions,
1344 apply_spec.n_instructions);
1347 *err_line = n_lines;
1349 *err_msg = "Pipeline instructions err.";
1353 apply_spec_free(&apply_spec);
1359 if (!strcmp(tokens[0], "extobj")) {
1360 status = extobj_statement_parse(&extobj_spec,
1369 status = rte_swx_pipeline_extern_object_config(p,
1371 extobj_spec.extern_type_name,
1372 extobj_spec.pragma);
1375 *err_line = n_lines;
1377 *err_msg = "Extern object config err.";
1381 extobj_spec_free(&extobj_spec);
1387 if (!strcmp(tokens[0], "struct")) {
1388 status = struct_statement_parse(&struct_spec,
1402 if (!strcmp(tokens[0], "header")) {
1403 status = header_statement_parse(&header_spec,
1412 status = rte_swx_pipeline_packet_header_register(p,
1414 header_spec.struct_type_name);
1417 *err_line = n_lines;
1419 *err_msg = "Header registration error.";
1423 header_spec_free(&header_spec);
1429 if (!strcmp(tokens[0], "metadata")) {
1430 status = metadata_statement_parse(&metadata_spec,
1439 status = rte_swx_pipeline_packet_metadata_register(p,
1440 metadata_spec.struct_type_name);
1443 *err_line = n_lines;
1445 *err_msg = "Meta-data reg err.";
1449 metadata_spec_free(&metadata_spec);
1455 if (!strcmp(tokens[0], "action")) {
1456 status = action_statement_parse(&action_spec,
1470 if (!strcmp(tokens[0], "table")) {
1471 status = table_statement_parse(&table_spec,
1485 if (!strcmp(tokens[0], "regarray")) {
1486 status = regarray_statement_parse(®array_spec,
1495 status = rte_swx_pipeline_regarray_config(p,
1498 regarray_spec.init_val);
1501 *err_line = n_lines;
1503 *err_msg = "Register array configuration error.";
1507 regarray_spec_free(®array_spec);
1513 if (!strcmp(tokens[0], "apply")) {
1514 status = apply_statement_parse(&block_mask,
1526 /* Anything else. */
1528 *err_line = n_lines;
1530 *err_msg = "Unknown statement.";
1535 /* Handle unfinished block. */
1538 *err_line = n_lines;
1540 *err_msg = "Missing }.";
1545 /* Pipeline build. */
1546 status = rte_swx_pipeline_build(p);
1549 *err_line = n_lines;
1551 *err_msg = "Pipeline build error.";
1558 extobj_spec_free(&extobj_spec);
1559 struct_spec_free(&struct_spec);
1560 header_spec_free(&header_spec);
1561 metadata_spec_free(&metadata_spec);
1562 action_spec_free(&action_spec);
1563 table_spec_free(&table_spec);
1564 regarray_spec_free(®array_spec);
1565 apply_spec_free(&apply_spec);