All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/9] pipeline: move specification data structures to internal header
@ 2022-07-18 13:07 Cristian Dumitrescu
  2022-07-18 13:07 ` [PATCH 2/9] pipeline: add pipeline specification data structure Cristian Dumitrescu
                   ` (9 more replies)
  0 siblings, 10 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:07 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Move all the pipeline object specification data structures to an
internal header file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 126 +------------------
 lib/pipeline/rte_swx_pipeline_spec.h | 176 +++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 125 deletions(-)
 create mode 100644 lib/pipeline/rte_swx_pipeline_spec.h

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 904b9eb471..5e07b4f794 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -9,7 +9,7 @@
 
 #include <rte_common.h>
 
-#include "rte_swx_pipeline.h"
+#include "rte_swx_pipeline_spec.h"
 
 #ifndef MAX_LINE_LENGTH
 #define MAX_LINE_LENGTH 2048
@@ -34,15 +34,7 @@
 
 /*
  * extobj.
- *
- * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
  */
-struct extobj_spec {
-	char *name;
-	char *extern_type_name;
-	char *pragma;
-};
-
 static void
 extobj_spec_free(struct extobj_spec *s)
 {
@@ -104,18 +96,7 @@ extobj_statement_parse(struct extobj_spec *s,
 /*
  * struct.
  *
- * struct STRUCT_TYPE_NAME {
- *	bit<SIZE> | varbit<SIZE> FIELD_NAME
- *	...
- * }
  */
-struct struct_spec {
-	char *name;
-	struct rte_swx_field_params *fields;
-	uint32_t n_fields;
-	int varbit;
-};
-
 static void
 struct_spec_free(struct struct_spec *s)
 {
@@ -293,13 +274,7 @@ struct_block_parse(struct struct_spec *s,
 /*
  * header.
  *
- * header HEADER_NAME instanceof STRUCT_TYPE_NAME
  */
-struct header_spec {
-	char *name;
-	char *struct_type_name;
-};
-
 static void
 header_spec_free(struct header_spec *s)
 {
@@ -351,12 +326,7 @@ header_statement_parse(struct header_spec *s,
 /*
  * metadata.
  *
- * metadata instanceof STRUCT_TYPE_NAME
  */
-struct metadata_spec {
-	char *struct_type_name;
-};
-
 static void
 metadata_spec_free(struct metadata_spec *s)
 {
@@ -400,18 +370,7 @@ metadata_statement_parse(struct metadata_spec *s,
 /*
  * action.
  *
- * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
- *	INSTRUCTION
- *	...
- * }
  */
-struct action_spec {
-	char *name;
-	char *args_struct_type_name;
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 action_spec_free(struct action_spec *s)
 {
@@ -540,29 +499,7 @@ action_block_parse(struct action_spec *s,
 /*
  * table.
  *
- * table TABLE_NAME {
- *	key {
- *		MATCH_FIELD_NAME exact | wildcard | lpm
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly ]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	instanceof TABLE_TYPE_NAME
- *	pragma ARGS
- *	size SIZE
- * }
  */
-struct table_spec {
-	char *name;
-	struct rte_swx_pipeline_table_params params;
-	char *recommended_table_type_name;
-	char *args;
-	uint32_t size;
-};
-
 static void
 table_spec_free(struct table_spec *s)
 {
@@ -1084,22 +1021,7 @@ table_block_parse(struct table_spec *s,
 /*
  * selector.
  *
- * selector SELECTOR_NAME {
- *	group_id FIELD_NAME
- *	selector {
- *		FIELD_NAME
- *		...
- *	}
- *	member_id FIELD_NAME
- *	n_groups N_GROUPS
- *	n_members_per_group N_MEMBERS_PER_GROUP
- * }
  */
-struct selector_spec {
-	char *name;
-	struct rte_swx_pipeline_selector_params params;
-};
-
 static void
 selector_spec_free(struct selector_spec *s)
 {
@@ -1385,31 +1307,7 @@ selector_block_parse(struct selector_spec *s,
 /*
  * learner.
  *
- * learner LEARNER_NAME {
- *	key {
- *		MATCH_FIELD_NAME
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	size SIZE
- *	timeout {
- *		TIMEOUT_IN_SECONDS
- *		...
- *	}
- * }
  */
-struct learner_spec {
-	char *name;
-	struct rte_swx_pipeline_learner_params params;
-	uint32_t size;
-	uint32_t *timeout;
-	uint32_t n_timeouts;
-};
-
 static void
 learner_spec_free(struct learner_spec *s)
 {
@@ -1958,14 +1856,7 @@ learner_block_parse(struct learner_spec *s,
 /*
  * regarray.
  *
- * regarray NAME size SIZE initval INITVAL
  */
-struct regarray_spec {
-	char *name;
-	uint64_t init_val;
-	uint32_t size;
-};
-
 static void
 regarray_spec_free(struct regarray_spec *s)
 {
@@ -2033,13 +1924,7 @@ regarray_statement_parse(struct regarray_spec *s,
 /*
  * metarray.
  *
- * metarray NAME size SIZE
  */
-struct metarray_spec {
-	char *name;
-	uint32_t size;
-};
-
 static void
 metarray_spec_free(struct metarray_spec *s)
 {
@@ -2095,16 +1980,7 @@ metarray_statement_parse(struct metarray_spec *s,
 /*
  * apply.
  *
- * apply {
- *	INSTRUCTION
- *	...
- * }
  */
-struct apply_spec {
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 apply_spec_free(struct apply_spec *s)
 {
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
new file mode 100644
index 0000000000..8458de878a
--- /dev/null
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Intel Corporation
+ */
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_common.h>
+
+#include <rte_swx_pipeline.h>
+
+/*
+ * extobj.
+ *
+ * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
+ */
+struct extobj_spec {
+	char *name;
+	char *extern_type_name;
+	char *pragma;
+};
+
+/*
+ * struct.
+ *
+ * struct STRUCT_TYPE_NAME {
+ *	bit<SIZE> | varbit<SIZE> FIELD_NAME
+ *	...
+ * }
+ */
+struct struct_spec {
+	char *name;
+	struct rte_swx_field_params *fields;
+	uint32_t n_fields;
+	int varbit;
+};
+
+/*
+ * header.
+ *
+ * header HEADER_NAME instanceof STRUCT_TYPE_NAME
+ */
+struct header_spec {
+	char *name;
+	char *struct_type_name;
+};
+
+/*
+ * metadata.
+ *
+ * metadata instanceof STRUCT_TYPE_NAME
+ */
+struct metadata_spec {
+	char *struct_type_name;
+};
+
+/*
+ * action.
+ *
+ * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct action_spec {
+	char *name;
+	char *args_struct_type_name;
+	const char **instructions;
+	uint32_t n_instructions;
+};
+
+/*
+ * table.
+ *
+ * table TABLE_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME exact | wildcard | lpm
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly ]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	instanceof TABLE_TYPE_NAME
+ *	pragma ARGS
+ *	size SIZE
+ * }
+ */
+struct table_spec {
+	char *name;
+	struct rte_swx_pipeline_table_params params;
+	char *recommended_table_type_name;
+	char *args;
+	uint32_t size;
+};
+
+/*
+ * selector.
+ *
+ * selector SELECTOR_NAME {
+ *	group_id FIELD_NAME
+ *	selector {
+ *		FIELD_NAME
+ *		...
+ *	}
+ *	member_id FIELD_NAME
+ *	n_groups N_GROUPS
+ *	n_members_per_group N_MEMBERS_PER_GROUP
+ * }
+ */
+struct selector_spec {
+	char *name;
+	struct rte_swx_pipeline_selector_params params;
+};
+
+/*
+ * learner.
+ *
+ * learner LEARNER_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	size SIZE
+ *	timeout {
+ *		TIMEOUT_IN_SECONDS
+ *		...
+ *	}
+ * }
+ */
+struct learner_spec {
+	char *name;
+	struct rte_swx_pipeline_learner_params params;
+	uint32_t size;
+	uint32_t *timeout;
+	uint32_t n_timeouts;
+};
+
+/*
+ * regarray.
+ *
+ * regarray NAME size SIZE initval INITVAL
+ */
+struct regarray_spec {
+	char *name;
+	uint64_t init_val;
+	uint32_t size;
+};
+
+/*
+ * metarray.
+ *
+ * metarray NAME size SIZE
+ */
+struct metarray_spec {
+	char *name;
+	uint32_t size;
+};
+
+/*
+ * apply.
+ *
+ * apply {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct apply_spec {
+	const char **instructions;
+	uint32_t n_instructions;
+};
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH 2/9] pipeline: add pipeline specification data structure
  2022-07-18 13:07 [PATCH 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
@ 2022-07-18 13:07 ` Cristian Dumitrescu
  2022-07-18 13:07 ` [PATCH 3/9] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:07 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add specification data structure for the entire pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 21 ++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h | 32 ++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 5e07b4f794..642091b678 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2082,6 +2082,27 @@ apply_block_parse(struct apply_spec *s,
 /*
  * Pipeline.
  */
+void
+pipeline_spec_free(struct pipeline_spec *s)
+{
+	if (!s)
+		return;
+
+	free(s->extobjs);
+	free(s->structs);
+	free(s->headers);
+	free(s->metadata);
+	free(s->actions);
+	free(s->tables);
+	free(s->selectors);
+	free(s->learners);
+	free(s->regarrays);
+	free(s->metarrays);
+	free(s->apply);
+
+	memset(s, 0, sizeof(struct pipeline_spec));
+}
+
 int
 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				 FILE *spec,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 8458de878a..e1170a33b1 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -174,3 +174,35 @@ struct apply_spec {
 	const char **instructions;
 	uint32_t n_instructions;
 };
+
+/*
+ * Pipeline.
+ */
+struct pipeline_spec {
+	struct extobj_spec *extobjs;
+	struct struct_spec *structs;
+	struct header_spec *headers;
+	struct metadata_spec *metadata;
+	struct action_spec *actions;
+	struct table_spec *tables;
+	struct selector_spec *selectors;
+	struct learner_spec *learners;
+	struct regarray_spec *regarrays;
+	struct metarray_spec *metarrays;
+	struct apply_spec *apply;
+
+	uint32_t n_extobjs;
+	uint32_t n_structs;
+	uint32_t n_headers;
+	uint32_t n_metadata;
+	uint32_t n_actions;
+	uint32_t n_tables;
+	uint32_t n_selectors;
+	uint32_t n_learners;
+	uint32_t n_regarrays;
+	uint32_t n_metarrays;
+	uint32_t n_apply;
+};
+
+void
+pipeline_spec_free(struct pipeline_spec *s);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH 3/9] pipeline: rework the specification file-based pipeline build
  2022-07-18 13:07 [PATCH 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
  2022-07-18 13:07 ` [PATCH 2/9] pipeline: add pipeline specification data structure Cristian Dumitrescu
@ 2022-07-18 13:07 ` Cristian Dumitrescu
  2022-07-18 13:07 ` [PATCH 4/9] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:07 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Rework the specification file-based pipeline build operation to first
parse the specification file into the previously introduced pipeline
specification data structure, then use this structure to configure
and build the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 478 +++++++++++++++++++++------
 lib/pipeline/rte_swx_pipeline_spec.h |   9 +
 2 files changed, 385 insertions(+), 102 deletions(-)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 642091b678..cbbcef852b 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2103,11 +2103,10 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg)
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg)
 {
 	struct extobj_spec extobj_spec = {0};
 	struct struct_spec struct_spec = {0};
@@ -2120,26 +2119,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	struct regarray_spec regarray_spec = {0};
 	struct metarray_spec metarray_spec = {0};
 	struct apply_spec apply_spec = {0};
-	uint32_t n_lines;
+	struct pipeline_spec *s = NULL;
+	uint32_t n_lines = 0;
 	uint32_t block_mask = 0;
-	int status;
+	int status = 0;
 
 	/* Check the input arguments. */
-	if (!p) {
+	if (!spec) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null pipeline argument.";
+			*err_msg = "Invalid input argument.";
 		status = -EINVAL;
 		goto error;
 	}
 
-	if (!spec) {
+	/* Memory allocation. */
+	s = calloc(sizeof(struct pipeline_spec), 1);
+	if (!s) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null specification file argument.";
-		status = -EINVAL;
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
 		goto error;
 	}
 
@@ -2200,6 +2202,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* struct block. */
 		if (block_mask & (1 << STRUCT_BLOCK)) {
+			struct struct_spec *new_structs;
+
 			status = struct_block_parse(&struct_spec,
 						    &block_mask,
 						    tokens,
@@ -2214,26 +2218,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_struct_type_register(p,
-				struct_spec.name,
-				struct_spec.fields,
-				struct_spec.n_fields,
-				struct_spec.varbit);
-			if (status) {
+			new_structs = realloc(s->structs,
+					      (s->n_structs + 1) * sizeof(struct struct_spec));
+			if (!new_structs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Struct registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			struct_spec_free(&struct_spec);
+			s->structs = new_structs;
+			memcpy(&s->structs[s->n_structs], &struct_spec, sizeof(struct struct_spec));
+			s->n_structs++;
+			memset(&struct_spec, 0, sizeof(struct struct_spec));
 
 			continue;
 		}
 
 		/* action block. */
 		if (block_mask & (1 << ACTION_BLOCK)) {
+			struct action_spec *new_actions;
+
 			status = action_block_parse(&action_spec,
 						    &block_mask,
 						    tokens,
@@ -2248,26 +2255,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_action_config(p,
-				action_spec.name,
-				action_spec.args_struct_type_name,
-				action_spec.instructions,
-				action_spec.n_instructions);
-			if (status) {
+			new_actions = realloc(s->actions,
+					      (s->n_actions + 1) * sizeof(struct action_spec));
+			if (!new_actions) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Action config error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			action_spec_free(&action_spec);
+			s->actions = new_actions;
+			memcpy(&s->actions[s->n_actions], &action_spec, sizeof(struct action_spec));
+			s->n_actions++;
+			memset(&action_spec, 0, sizeof(struct action_spec));
 
 			continue;
 		}
 
 		/* table block. */
 		if (block_mask & (1 << TABLE_BLOCK)) {
+			struct table_spec *new_tables;
+
 			status = table_block_parse(&table_spec,
 						   &block_mask,
 						   tokens,
@@ -2282,27 +2292,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_table_config(p,
-				table_spec.name,
-				&table_spec.params,
-				table_spec.recommended_table_type_name,
-				table_spec.args,
-				table_spec.size);
-			if (status) {
+			new_tables = realloc(s->tables,
+					     (s->n_tables + 1) * sizeof(struct table_spec));
+			if (!new_tables) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			table_spec_free(&table_spec);
+			s->tables = new_tables;
+			memcpy(&s->tables[s->n_tables], &table_spec, sizeof(struct table_spec));
+			s->n_tables++;
+			memset(&table_spec, 0, sizeof(struct table_spec));
 
 			continue;
 		}
 
 		/* selector block. */
 		if (block_mask & (1 << SELECTOR_BLOCK)) {
+			struct selector_spec *new_selectors;
+
 			status = selector_block_parse(&selector_spec,
 						      &block_mask,
 						      tokens,
@@ -2317,24 +2329,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_selector_config(p,
-				selector_spec.name,
-				&selector_spec.params);
-			if (status) {
+			new_selectors = realloc(s->selectors,
+						(s->n_selectors + 1) * sizeof(struct selector_spec));
+			if (!new_selectors) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Selector configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			selector_spec_free(&selector_spec);
+			s->selectors = new_selectors;
+			memcpy(&s->selectors[s->n_selectors],
+			       &selector_spec,
+			       sizeof(struct selector_spec));
+			s->n_selectors++;
+			memset(&selector_spec, 0, sizeof(struct selector_spec));
 
 			continue;
 		}
 
 		/* learner block. */
 		if (block_mask & (1 << LEARNER_BLOCK)) {
+			struct learner_spec *new_learners;
+
 			status = learner_block_parse(&learner_spec,
 						     &block_mask,
 						     tokens,
@@ -2349,27 +2368,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_learner_config(p,
-				learner_spec.name,
-				&learner_spec.params,
-				learner_spec.size,
-				learner_spec.timeout,
-				learner_spec.n_timeouts);
-			if (status) {
+			new_learners = realloc(s->learners,
+					       (s->n_learners + 1) * sizeof(struct learner_spec));
+			if (!new_learners) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Learner table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			learner_spec_free(&learner_spec);
+			s->learners = new_learners;
+			memcpy(&s->learners[s->n_learners],
+			       &learner_spec,
+			       sizeof(struct learner_spec));
+			s->n_learners++;
+			memset(&learner_spec, 0, sizeof(struct learner_spec));
 
 			continue;
 		}
 
 		/* apply block. */
 		if (block_mask & (1 << APPLY_BLOCK)) {
+			struct apply_spec *new_apply;
+
 			status = apply_block_parse(&apply_spec,
 						   &block_mask,
 						   tokens,
@@ -2384,24 +2407,28 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_instructions_config(p,
-				apply_spec.instructions,
-				apply_spec.n_instructions);
-			if (status) {
+			new_apply = realloc(s->apply, (s->n_apply + 1) * sizeof(struct apply_spec));
+			if (!new_apply) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Pipeline instructions err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			apply_spec_free(&apply_spec);
+			s->apply = new_apply;
+			memcpy(&s->apply[s->n_apply], &apply_spec, sizeof(struct apply_spec));
+			s->n_apply++;
+			memset(&apply_spec, 0, sizeof(struct apply_spec));
 
 			continue;
 		}
 
 		/* extobj. */
 		if (!strcmp(tokens[0], "extobj")) {
+			struct extobj_spec *new_extobjs;
+
 			status = extobj_statement_parse(&extobj_spec,
 							tokens,
 							n_tokens,
@@ -2411,19 +2438,21 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_extern_object_config(p,
-				extobj_spec.name,
-				extobj_spec.extern_type_name,
-				extobj_spec.pragma);
-			if (status) {
+			new_extobjs = realloc(s->extobjs,
+					      (s->n_extobjs + 1) * sizeof(struct extobj_spec));
+			if (!new_extobjs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Extern object config err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			extobj_spec_free(&extobj_spec);
+			s->extobjs = new_extobjs;
+			memcpy(&s->extobjs[s->n_extobjs], &extobj_spec, sizeof(struct extobj_spec));
+			s->n_extobjs++;
+			memset(&extobj_spec, 0, sizeof(struct extobj_spec));
 
 			continue;
 		}
@@ -2445,6 +2474,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* header. */
 		if (!strcmp(tokens[0], "header")) {
+			struct header_spec *new_headers;
+
 			status = header_statement_parse(&header_spec,
 							tokens,
 							n_tokens,
@@ -2454,24 +2485,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_header_register(p,
-				header_spec.name,
-				header_spec.struct_type_name);
-			if (status) {
+			new_headers = realloc(s->headers,
+					      (s->n_headers + 1) * sizeof(struct header_spec));
+			if (!new_headers) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Header registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			header_spec_free(&header_spec);
+			s->headers = new_headers;
+			memcpy(&s->headers[s->n_headers], &header_spec, sizeof(struct header_spec));
+			s->n_headers++;
+			memset(&header_spec, 0, sizeof(struct header_spec));
 
 			continue;
 		}
 
 		/* metadata. */
 		if (!strcmp(tokens[0], "metadata")) {
+			struct metadata_spec *new_metadata;
+
 			status = metadata_statement_parse(&metadata_spec,
 							  tokens,
 							  n_tokens,
@@ -2481,17 +2517,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_metadata_register(p,
-				metadata_spec.struct_type_name);
-			if (status) {
+			new_metadata = realloc(s->metadata,
+					       (s->n_metadata + 1) * sizeof(struct metadata_spec));
+			if (!new_metadata) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meta-data reg err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metadata_spec_free(&metadata_spec);
+			s->metadata = new_metadata;
+			memcpy(&s->metadata[s->n_metadata],
+			       &metadata_spec,
+			       sizeof(struct metadata_spec));
+			s->n_metadata++;
+			memset(&metadata_spec, 0, sizeof(struct metadata_spec));
 
 			continue;
 		}
@@ -2558,6 +2600,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* regarray. */
 		if (!strcmp(tokens[0], "regarray")) {
+			struct regarray_spec *new_regarrays;
+
 			status = regarray_statement_parse(&regarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2567,25 +2611,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_regarray_config(p,
-				regarray_spec.name,
-				regarray_spec.size,
-				regarray_spec.init_val);
-			if (status) {
+			new_regarrays = realloc(s->regarrays,
+				(s->n_regarrays + 1) * sizeof(struct regarray_spec));
+			if (!new_regarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Register array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			regarray_spec_free(&regarray_spec);
+			s->regarrays = new_regarrays;
+			memcpy(&s->regarrays[s->n_regarrays],
+			       &regarray_spec,
+			       sizeof(struct regarray_spec));
+			s->n_regarrays++;
+			memset(&regarray_spec, 0, sizeof(struct regarray_spec));
 
 			continue;
 		}
 
 		/* metarray. */
 		if (!strcmp(tokens[0], "metarray")) {
+			struct metarray_spec *new_metarrays;
+
 			status = metarray_statement_parse(&metarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2595,18 +2645,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_metarray_config(p,
-				metarray_spec.name,
-				metarray_spec.size);
-			if (status) {
+			new_metarrays = realloc(s->metarrays,
+				(s->n_metarrays + 1) * sizeof(struct metarray_spec));
+			if (!new_metarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meter array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metarray_spec_free(&metarray_spec);
+			s->metarrays = new_metarrays;
+			memcpy(&s->metarrays[s->n_metarrays],
+			       &metarray_spec,
+			       sizeof(struct metarray_spec));
+			s->n_metarrays++;
+			memset(&metarray_spec, 0, sizeof(struct metarray_spec));
 
 			continue;
 		}
@@ -2644,17 +2699,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 		goto error;
 	}
 
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = n_lines;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
+	return s;
 
 error:
 	extobj_spec_free(&extobj_spec);
@@ -2668,5 +2713,234 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	regarray_spec_free(&regarray_spec);
 	metarray_spec_free(&metarray_spec);
 	apply_spec_free(&apply_spec);
+	pipeline_spec_free(s);
+
+	return NULL;
+}
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg)
+{
+	uint32_t i;
+	int status = 0;
+
+	/* extobj. */
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		status = rte_swx_pipeline_extern_object_config(p,
+			extobj_spec->name,
+			extobj_spec->extern_type_name,
+			extobj_spec->pragma);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Extern object configuration error.";
+			return status;
+		}
+	}
+
+	/* regarray. */
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		status = rte_swx_pipeline_regarray_config(p,
+			regarray_spec->name,
+			regarray_spec->size,
+			regarray_spec->init_val);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Register array configuration error.";
+			return status;
+		}
+	}
+
+	/* metarray. */
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		status = rte_swx_pipeline_metarray_config(p,
+			metarray_spec->name,
+			metarray_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meter array configuration error.";
+			return status;
+		}
+	}
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		status = rte_swx_pipeline_struct_type_register(p,
+			struct_spec->name,
+			struct_spec->fields,
+			struct_spec->n_fields,
+			struct_spec->varbit);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Struct type registration error.";
+			return status;
+		}
+	}
+
+	/* header. */
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		status = rte_swx_pipeline_packet_header_register(p,
+			header_spec->name,
+			header_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Header configuration error.";
+			return status;
+		}
+	}
+
+	/* metadata. */
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		status = rte_swx_pipeline_packet_metadata_register(p,
+			metadata_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meta-data registration error.";
+			return status;
+		}
+	}
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		status = rte_swx_pipeline_action_config(p,
+			action_spec->name,
+			action_spec->args_struct_type_name,
+			action_spec->instructions,
+			action_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Action configuration error.";
+			return status;
+		}
+	}
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		status = rte_swx_pipeline_table_config(p,
+			table_spec->name,
+			&table_spec->params,
+			table_spec->recommended_table_type_name,
+			table_spec->args,
+			table_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Table configuration error.";
+			return status;
+		}
+	}
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		status = rte_swx_pipeline_selector_config(p,
+			selector_spec->name,
+			&selector_spec->params);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Selector table configuration error.";
+			return status;
+		}
+	}
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		status = rte_swx_pipeline_learner_config(p,
+			learner_spec->name,
+			&learner_spec->params,
+			learner_spec->size,
+			learner_spec->timeout,
+			learner_spec->n_timeouts);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Learner table configuration error.";
+			return status;
+		}
+	}
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+
+		status = rte_swx_pipeline_instructions_config(p,
+			apply_spec->instructions,
+			apply_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline instructions configuration error.";
+			return status;
+		}
+	}
+
+	return 0;
+}
+
+int
+rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
+				 FILE *spec_file,
+				 uint32_t *err_line,
+				 const char **err_msg)
+{
+	struct pipeline_spec *s = NULL;
+	int status = 0;
+
+	/* Check the input arguments. */
+	if (!p || !spec_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Spec file parse. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Pipeline configure. */
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto error;
+	}
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline build error.";
+		goto error;
+	}
+
+	return 0;
+
+error:
+	pipeline_spec_free(s);
 	return status;
 }
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index e1170a33b1..4f3a0b5958 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,3 +206,12 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg);
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH 4/9] pipeline: generate the code for pipeline specification structure
  2022-07-18 13:07 [PATCH 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
  2022-07-18 13:07 ` [PATCH 2/9] pipeline: add pipeline specification data structure Cristian Dumitrescu
  2022-07-18 13:07 ` [PATCH 3/9] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
@ 2022-07-18 13:07 ` Cristian Dumitrescu
  2022-07-18 13:07 ` [PATCH 5/9] pipeline: add API for pipeline code generation Cristian Dumitrescu
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:07 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add support to export the pipeline specification data structure to a C
source code file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 621 +++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h |   5 +
 2 files changed, 626 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index cbbcef852b..05cf952816 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2020 Intel Corporation
  */
 #include <stdint.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -2103,6 +2104,626 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
+static const char *
+match_type_string_get(enum rte_swx_table_match_type match_type)
+{
+	switch (match_type) {
+		case RTE_SWX_TABLE_MATCH_WILDCARD: return "RTE_SWX_TABLE_MATCH_WILDCARD";
+		case RTE_SWX_TABLE_MATCH_LPM: return "RTE_SWX_TABLE_MATCH_LPM";
+		case RTE_SWX_TABLE_MATCH_EXACT: return "RTE_SWX_TABLE_MATCH_EXACT";
+		default: return "RTE_SWX_TABLE_MATCH_UNKNOWN";
+	}
+}
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s)
+{
+	uint32_t i;
+
+	/* Check the input arguments. */
+	if (!f || !s)
+		return;
+
+	/* extobj. */
+	fprintf(f, "static struct extobj_spec extobjs[] = {\n");
+
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", extobj_spec->name);
+		fprintf(f, "\t\t.extern_type_name = \"%s\",\n", extobj_spec->extern_type_name);
+		if (extobj_spec->pragma)
+			fprintf(f, "\t\t.pragma = \"%s\",\n", extobj_spec->pragma);
+		else
+			fprintf(f, "\t\t.pragma = NULL,\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* regarray. */
+	fprintf(f, "static struct regarray_spec regarrays[] = {\n");
+
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", regarray_spec->name);
+		fprintf(f, "\t\t.init_val = %" PRIu64 ",\n", regarray_spec->init_val);
+		fprintf(f, "\t\t.size = %u,\n", regarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metarray. */
+	fprintf(f, "static struct metarray_spec metarrays[] = {\n");
+
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", metarray_spec->name);
+		fprintf(f, "\t\t.size = %u,\n", metarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+		uint32_t j;
+
+		fprintf(f, "static struct rte_swx_field_params struct_%s_fields[] = {\n",
+			struct_spec->name);
+
+		for (j = 0; j < struct_spec->n_fields; j++) {
+			struct rte_swx_field_params *field = &struct_spec->fields[j];
+
+			fprintf(f, "\t[%d] = {\n", j);
+			fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+			fprintf(f, "\t\t.n_bits = %u,\n", field->n_bits);
+			fprintf(f, "\t},\n");
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct struct_spec structs[] = {\n");
+
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", struct_spec->name);
+		fprintf(f, "\t\t.fields = struct_%s_fields,\n", struct_spec->name);
+		fprintf(f, "\t\t.n_fields = "
+			"sizeof(struct_%s_fields) / sizeof(struct_%s_fields[0]),\n",
+			struct_spec->name,
+			struct_spec->name);
+		fprintf(f, "\t\t.varbit = %d,\n", struct_spec->varbit);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* header. */
+	fprintf(f, "static struct header_spec headers[] = {\n");
+
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", header_spec->name);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", header_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metadata. */
+	fprintf(f, "static struct metadata_spec metadata[] = {\n");
+
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", metadata_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *action_%s_initial_instructions[] = {\n",
+			action_spec->name);
+
+		for (j = 0; j < action_spec->n_instructions; j++) {
+			const char *instr = action_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct action_spec actions[] = {\n");
+
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", action_spec->name);
+
+		if (action_spec->args_struct_type_name)
+			fprintf(f, "\t\t.args_struct_type_name = \"%s\",\n",
+				action_spec->args_struct_type_name);
+		else
+			fprintf(f, "\t\t.args_struct_type_name = NULL,\n");
+
+		fprintf(f, "\t\t.instructions = action_%s_initial_instructions,\n",
+			action_spec->name);
+		fprintf(f, "\t\t.n_instructions = "
+			"sizeof(action_%s_initial_instructions) / "
+			"sizeof(action_%s_initial_instructions[0]),\n",
+			action_spec->name,
+			action_spec->name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+		uint32_t j;
+
+		/* fields. */
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "static struct rte_swx_match_field_params "
+				"table_%s_fields[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_fields; j++) {
+				struct rte_swx_match_field_params *field =
+					&table_spec->params.fields[j];
+
+				fprintf(f, "\t[%d] = {\n", j);
+				fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+				fprintf(f, "\t\t.match_type = %s,\n",
+					match_type_string_get(field->match_type));
+				fprintf(f, "\t},\n");
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (table_spec->params.action_names && table_spec->params.n_actions) {
+			fprintf(f, "static const char *table_%s_action_names[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				const char *action_name = table_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (table_spec->params.action_is_for_table_entries &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_table_entries[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (table_spec->params.action_is_for_default_entry &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_default_entry[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct table_spec tables[] = {\n");
+
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", table_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.fields = table_%s_fields,\n", table_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(table_%s_fields) / sizeof(table_%s_fields[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.fields = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (table_spec->params.action_names && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = table_%s_action_names,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (table_spec->params.action_is_for_table_entries && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"table_%s_action_is_for_table_entries,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (table_spec->params.action_is_for_default_entry && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"table_%s_action_is_for_default_entry,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = sizeof(table_%s_action_names) / "
+				"sizeof(table_%s_action_names[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = 0,\n");
+
+		if (table_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				table_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (table_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				table_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			table_spec->params.default_action_is_const);
+		fprintf(f, "\t\t},\n");
+
+		if (table_spec->recommended_table_type_name)
+			fprintf(f, "\t\t.recommended_table_type_name = \"%s\",\n",
+				table_spec->recommended_table_type_name);
+		else
+			fprintf(f, "\t\t.recommended_table_type_name = NULL,\n");
+
+		if (table_spec->args)
+			fprintf(f, "\t\t.args = \"%s\",\n", table_spec->args);
+		else
+			fprintf(f, "\t\t.args = NULL,\n");
+
+		fprintf(f, "\t\t.size = %u,\n", table_spec->size);
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+		uint32_t j;
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "static const char *selector_%s_field_names[] = {\n",
+				selector_spec->name);
+
+			for (j = 0; j < selector_spec->params.n_selector_fields; j++) {
+				const char *field_name =
+					selector_spec->params.selector_field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct selector_spec selectors[] = {\n");
+
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+
+		fprintf(f, "\t\t.name = \"%s\",\n", selector_spec->name);
+		fprintf(f, "\t\t.params = {\n");
+
+		if (selector_spec->params.group_id_field_name)
+			fprintf(f, "\t\t\t.group_id_field_name = \"%s\",\n",
+				selector_spec->params.group_id_field_name);
+		else
+			fprintf(f, "\t\t\t.group_id_field_name = NULL,\n");
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "\t\t\t.selector_field_names = selector_%s_field_names,\n",
+				selector_spec->name);
+			fprintf(f, "\t\t\t.n_selector_fields = "
+				"sizeof(selector_%s_field_names) / sizeof(selector_%s_field_names[0]),\n",
+				selector_spec->name,
+				selector_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.selector_field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_selector_fields = 0,\n");
+		}
+
+		if (selector_spec->params.member_id_field_name)
+			fprintf(f, "\t\t\t.member_id_field_name = \"%s\",\n",
+				selector_spec->params.member_id_field_name);
+		else
+			fprintf(f, "\t\t\t.member_id_field_name = NULL,\n");
+
+		fprintf(f, "\t\t\t.n_groups_max = %u,\n", selector_spec->params.n_groups_max);
+
+		fprintf(f, "\t\t\t.n_members_per_group_max = %u,\n",
+			selector_spec->params.n_members_per_group_max);
+
+		fprintf(f, "\t\t},\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+		uint32_t j;
+
+		/* field_names. */
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "static const char *learner_%s_field_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_fields; j++) {
+				const char *field_name = learner_spec->params.field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (learner_spec->params.action_names && learner_spec->params.n_actions) {
+			fprintf(f, "static const char *learner_%s_action_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				const char *action_name = learner_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_table_entries[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_default_entry[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* timeout. */
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "static uint32_t learner_%s_timeout[] = {\n", learner_spec->name);
+
+			for (j = 0; j < learner_spec->n_timeouts; j++) {
+				uint32_t value = learner_spec->timeout[j];
+
+				fprintf(f, "\t[%d] = %u,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct learner_spec learners[] = {\n");
+
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", learner_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.field_names = learner_%s_field_names,\n",
+				learner_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(learner_%s_field_names) / "
+				"sizeof(learner_%s_field_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = learner_%s_action_names,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"learner_%s_action_is_for_table_entries,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"learner_%s_action_is_for_default_entry,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = "
+				"sizeof(learner_%s_action_names) / sizeof(learner_%s_action_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = NULL,\n");
+
+		if (learner_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				learner_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (learner_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				learner_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			learner_spec->params.default_action_is_const);
+
+		fprintf(f, "\t\t},\n");
+
+		fprintf(f, "\t\t.size = %u,\n", learner_spec->size);
+
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "\t\t.timeout = learner_%s_timeout,\n", learner_spec->name);
+			fprintf(f, "\t\t\t.n_timeouts = "
+				"sizeof(learner_%s_timeout) / sizeof(learner_%s_timeout[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t.timeout = NULL,\n");
+			fprintf(f, "\t\t\t.n_timeouts = 0,\n");
+		}
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *apply%u_initial_instructions[] = {\n", i);
+
+		for (j = 0; j < apply_spec->n_instructions; j++) {
+			const char *instr = apply_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct apply_spec apply[] = {\n");
+
+	for (i = 0; i < s->n_apply; i++) {
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t.instructions = apply%u_initial_instructions,\n", i);
+		fprintf(f, "\t.n_instructions = "
+			"sizeof(apply%u_initial_instructions) / "
+			"sizeof(apply%u_initial_instructions[0]),\n",
+			i,
+			i);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* pipeline. */
+	fprintf(f, "struct pipeline_spec pipeline_spec = {\n");
+	fprintf(f, "\t.extobjs = extobjs,\n");
+	fprintf(f, "\t.structs = structs,\n");
+	fprintf(f, "\t.headers = headers,\n");
+	fprintf(f, "\t.metadata = metadata,\n");
+	fprintf(f, "\t.actions = actions,\n");
+	fprintf(f, "\t.tables = tables,\n");
+	fprintf(f, "\t.selectors = selectors,\n");
+	fprintf(f, "\t.learners = learners,\n");
+	fprintf(f, "\t.regarrays = regarrays,\n");
+	fprintf(f, "\t.metarrays = metarrays,\n");
+	fprintf(f, "\t.apply = apply,\n");
+	fprintf(f, "\t.n_extobjs = sizeof(extobjs) / sizeof(extobjs[0]),\n");
+	fprintf(f, "\t.n_structs = sizeof(structs) / sizeof(structs[0]),\n");
+	fprintf(f, "\t.n_headers = sizeof(headers) / sizeof(headers[0]),\n");
+	fprintf(f, "\t.n_metadata = sizeof(metadata) / sizeof(metadata[0]),\n");
+	fprintf(f, "\t.n_actions = sizeof(actions) / sizeof(actions[0]),\n");
+	fprintf(f, "\t.n_tables = sizeof(tables) / sizeof(tables[0]),\n");
+	fprintf(f, "\t.n_selectors = sizeof(selectors) / sizeof(selectors[0]),\n");
+	fprintf(f, "\t.n_learners = sizeof(learners) / sizeof(learners[0]),\n");
+	fprintf(f, "\t.n_regarrays = sizeof(regarrays) / sizeof(regarrays[0]),\n");
+	fprintf(f, "\t.n_metarrays = sizeof(metarrays) / sizeof(metarrays[0]),\n");
+	fprintf(f, "\t.n_apply = sizeof(apply) / sizeof(apply[0]),\n");
+	fprintf(f, "};\n");
+}
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 4f3a0b5958..707b99ba09 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,6 +206,11 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s);
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH 5/9] pipeline: add API for pipeline code generation
  2022-07-18 13:07 [PATCH 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                   ` (2 preceding siblings ...)
  2022-07-18 13:07 ` [PATCH 4/9] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
@ 2022-07-18 13:07 ` Cristian Dumitrescu
  2022-07-18 13:07 ` [PATCH 6/9] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:07 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the C code generation for the pipeline was hidden under
the hood; now, we make this an explicit API operation. Besides the
functions for the pipeline actions and the pipeline instructions,
the generated C source code now includes the pipeline specification
structure required for the pipeline configuration operations.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline.c | 94 +++++++++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline.h | 25 +++++++++
 lib/pipeline/version.map        |  3 ++
 3 files changed, 122 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index 3e1c6e9edb..52760111fd 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -18,6 +18,7 @@
 #include <rte_swx_table_wm.h>
 
 #include "rte_swx_pipeline_internal.h"
+#include "rte_swx_pipeline_spec.h"
 
 #define CHECK(condition, err_code)                                             \
 do {                                                                           \
@@ -13476,3 +13477,96 @@ pipeline_compile(struct rte_swx_pipeline *p)
 
 	return status;
 }
+
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg)
+
+{
+	struct rte_swx_pipeline *p = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!spec_file || !code_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	status = rte_swx_pipeline_config(&p, 0);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline configuration error.";
+		goto free;
+	}
+
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto free;
+	}
+
+	/*
+	 * Pipeline code generation.
+	 */
+
+	/* Instruction Group List (IGL) computation: the pipeline configuration must be done first,
+	 * but there is no need for the pipeline build to be done as well.
+	 */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
+		goto free;
+	}
+
+	/* Header file inclusion. */
+	fprintf(code_file, "#include \"rte_swx_pipeline_internal.h\"\n");
+	fprintf(code_file, "#include \"rte_swx_pipeline_spec.h\"\n\n");
+
+	/* Code generation for the pipeline specification. */
+	pipeline_spec_codegen(code_file, s);
+	fprintf(code_file, "\n");
+
+	/* Code generation for the action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		fprintf(code_file, "/**\n * Action %s\n */\n\n", a->name);
+
+		action_data_codegen(a, code_file);
+		fprintf(code_file, "\n");
+
+		action_instr_codegen(a, code_file);
+		fprintf(code_file, "\n");
+	}
+
+	/* Code generation for the pipeline instructions. */
+	instruction_group_list_codegen(igl, p, code_file);
+
+free:
+	instruction_group_list_free(igl);
+	rte_swx_pipeline_free(p);
+	pipeline_spec_free(s);
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index c41ca5cb15..2bd019b05f 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -941,6 +941,31 @@ __rte_experimental
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p);
 
+/**
+ * Pipeline C code generate based on input specification file
+ *
+ * @param[in] spec_file
+ *   Pipeline specification file (.spec) provided as input.
+ * @param[in] code_file
+ *   Pipeline C language file (.c) to be generated.
+ * @param[out] err_line
+ *   In case of error and non-NULL, the line number within the *spec* file where
+ *   the error occurred. The first line number in the file is 1.
+ * @param[out] err_msg
+ *   In case of error and non-NULL, the error message.
+ * @return
+ *   0 on success or the following error codes otherwise:
+ *   -EINVAL: Invalid argument;
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -EEXIST: Resource with the same name already exists.
+ */
+__rte_experimental
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg);
+
 /**
  * Pipeline build from specification file
  *
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 8312307a7a..51165d48cf 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -145,4 +145,7 @@ EXPERIMENTAL {
 	rte_swx_ctl_pipeline_learner_timeout_get;
 	rte_swx_ctl_pipeline_learner_timeout_set;
 	rte_swx_pipeline_hash_func_register;
+
+	#added in 22.11
+	rte_swx_pipeline_codegen;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH 6/9] pipeline: add API for shared library-based pipeline build
  2022-07-18 13:07 [PATCH 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                   ` (3 preceding siblings ...)
  2022-07-18 13:07 ` [PATCH 5/9] pipeline: add API for pipeline code generation Cristian Dumitrescu
@ 2022-07-18 13:07 ` Cristian Dumitrescu
  2022-07-18 13:07 ` [PATCH 7/9] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:07 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the pipeline build operation was done based on the
specification file (typically produced by the P4 compiler), then the C
code with optimized functions for the pipeline actions and
instructions was generated, built into a shared object library, loaded
and installed into the pipeline in a completely hardcoded and
non-customizable way.

Now, this process is split into three explicit stages:
i) code generation (specification file -> C file);
ii) code build (C file -> shared object library);
iii) code installation (library load into the pipeline).

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c              |  20 +-
 lib/pipeline/rte_swx_pipeline.c      | 289 +++++++++------------------
 lib/pipeline/rte_swx_pipeline.h      |  22 +-
 lib/pipeline/rte_swx_pipeline_spec.c |  51 -----
 lib/pipeline/version.map             |   2 +-
 5 files changed, 108 insertions(+), 276 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index ad553f19ab..1f75b5dc9d 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -984,7 +984,7 @@ cmd_pipeline_port_out(char **tokens,
 }
 
 static const char cmd_pipeline_build_help[] =
-"pipeline <pipeline_name> build <spec_file>\n";
+"pipeline <pipeline_name> build <lib_file>\n";
 
 static void
 cmd_pipeline_build(char **tokens,
@@ -994,9 +994,6 @@ cmd_pipeline_build(char **tokens,
 	void *obj)
 {
 	struct pipeline *p = NULL;
-	FILE *spec = NULL;
-	uint32_t err_line;
-	const char *err_msg;
 	int status;
 
 	if (n_tokens != 4) {
@@ -1010,20 +1007,9 @@ cmd_pipeline_build(char **tokens,
 		return;
 	}
 
-	spec = fopen(tokens[3], "r");
-	if (!spec) {
-		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
-		return;
-	}
-
-	status = rte_swx_pipeline_build_from_spec(p->p,
-		spec,
-		&err_line,
-		&err_msg);
-	fclose(spec);
+	status = rte_swx_pipeline_build_from_lib(p->p, tokens[3]);
 	if (status) {
-		snprintf(out, out_size, "Error %d at line %u: %s\n.",
-			status, err_line, err_msg);
+		snprintf(out, out_size, "Pipeline build error (%d).", status);
 		return;
 	}
 
diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index 52760111fd..03414bfd1f 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -9807,9 +9807,6 @@ rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p,
 	return 0;
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p);
-
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 {
@@ -9899,8 +9896,6 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 
 	p->build_done = 1;
 
-	pipeline_compile(p);
-
 	return 0;
 
 error:
@@ -13222,160 +13217,6 @@ instruction_group_list_custom_instructions_count(struct instruction_group_list *
 	return n_custom_instr;
 }
 
-static int
-pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	FILE *f = NULL;
-
-	/* Create the .c file. */
-	f = fopen("/tmp/pipeline.c", "w");
-	if (!f)
-		return -EIO;
-
-	/* Include the .h file. */
-	fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n");
-
-	/* Add the code for each action. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		fprintf(f, "/**\n * Action %s\n */\n\n", a->name);
-
-		action_data_codegen(a, f);
-
-		fprintf(f, "\n");
-
-		action_instr_codegen(a, f);
-
-		fprintf(f, "\n");
-	}
-
-	/* Add the pipeline code. */
-	instruction_group_list_codegen(igl, p, f);
-
-	/* Close the .c file. */
-	fclose(f);
-
-	return 0;
-}
-
-#ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE
-#define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096
-#endif
-
-static int
-pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	struct instruction_group *g;
-	char *dir_in, *buffer = NULL;
-	const char *dir_out;
-	int status = 0;
-
-	/* Get the environment variables. */
-	dir_in = getenv("RTE_INSTALL_DIR");
-	if (!dir_in) {
-		status = -EINVAL;
-		goto free;
-	}
-
-	dir_out = "/tmp";
-
-	/* Memory allocation for the command buffer. */
-	buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE);
-	if (!buffer) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c "
-		 "-I %s/lib/pipeline "
-		 "-I %s/lib/eal/include "
-		 "-I %s/lib/eal/x86/include "
-		 "-I %s/lib/eal/include/generic "
-		 "-I %s/lib/meter "
-		 "-I %s/lib/port "
-		 "-I %s/lib/table "
-		 "-I %s/lib/pipeline "
-		 "-I %s/config "
-		 "-I %s/build "
-		 "-I %s/lib/eal/linux/include "
-		 ">%s/pipeline.log 2>&1 "
-		 "&& "
-		 "gcc -shared %s/pipeline.o -o %s/libpipeline.so "
-		 ">>%s/pipeline.log 2>&1",
-		 dir_out,
-		 dir_out,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_out,
-		 dir_out,
-		 dir_out,
-		 dir_out);
-
-	/* Build the shared object library. */
-	status = system(buffer);
-	if (status)
-		goto free;
-
-	/* Open library. */
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "%s/libpipeline.so",
-		 dir_out);
-
-	p->lib = dlopen(buffer, RTLD_LAZY);
-	if (!p->lib) {
-		status = -EIO;
-		goto free;
-	}
-
-	/* Get the action function symbols. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name);
-
-		p->action_funcs[a->id] = dlsym(p->lib, buffer);
-		if (!p->action_funcs[a->id]) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-	/* Get the pipeline function symbols. */
-	TAILQ_FOREACH(g, igl, node) {
-		if (g->first_instr_id == g->last_instr_id)
-			continue;
-
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id);
-
-		g->func = dlsym(p->lib, buffer);
-		if (!g->func) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-free:
-	if (status && p->lib) {
-		dlclose(p->lib);
-		p->lib = NULL;
-	}
-
-	free(buffer);
-
-	return status;
-}
-
 static int
 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused,
 		      struct instruction_group_list *igl)
@@ -13443,41 +13284,6 @@ pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
 	instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions);
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p)
-{
-	struct instruction_group_list *igl = NULL;
-	int status = 0;
-
-	igl = instruction_group_list_create(p);
-	if (!igl) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	/* Code generation. */
-	status = pipeline_codegen(p, igl);
-	if (status)
-		goto free;
-
-	/* Build and load the shared object library. */
-	status = pipeline_libload(p, igl);
-	if (status)
-		goto free;
-
-	/* Adjust instructions. */
-	status = pipeline_adjust_check(p, igl);
-	if (status)
-		goto free;
-
-	pipeline_adjust(p, igl);
-
-free:
-	instruction_group_list_free(igl);
-
-	return status;
-}
-
 int
 rte_swx_pipeline_codegen(FILE *spec_file,
 			 FILE *code_file,
@@ -13570,3 +13376,98 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 
 	return status;
 }
+
+int
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline *p,
+				const char *lib_file_name)
+{
+	void *lib = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	struct instruction_group *g;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!p || p->build_done || !lib_file_name || !lib_file_name[0]) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Open the library. */
+	lib = dlopen(lib_file_name, RTLD_LAZY);
+	if (!lib) {
+		status = -EIO;
+		goto free;
+	}
+
+	/* Get the pipeline specification structure from the library. */
+	s = dlsym(lib, "pipeline_spec");
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration based on the specification structure. */
+	status = pipeline_spec_configure(p, s, NULL);
+	if (status)
+		goto free;
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status)
+		goto free;
+
+	/* Action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		snprintf(name, sizeof(name), "action_%s_run", a->name);
+
+		p->action_funcs[a->id] = dlsym(lib, name);
+		if (!p->action_funcs[a->id]) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	/* Pipeline instructions. */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		status = -ENOMEM;
+		goto free;
+	}
+
+	TAILQ_FOREACH(g, igl, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		if (g->first_instr_id == g->last_instr_id)
+			continue;
+
+		snprintf(name, sizeof(name), "pipeline_func_%u", g->group_id);
+
+		g->func = dlsym(lib, name);
+		if (!g->func) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	status = pipeline_adjust_check(p, igl);
+	if (status)
+		goto free;
+
+	pipeline_adjust(p, igl);
+
+	p->lib = lib;
+
+free:
+	if (status && lib) {
+		dlclose(lib);
+		p->lib = NULL;
+	}
+
+	instruction_group_list_free(igl);
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index 2bd019b05f..cb834cd64d 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -967,30 +967,26 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 			 const char **err_msg);
 
 /**
- * Pipeline build from specification file
+ * Pipeline build from shared object library
+ *
+ * The shared object library must be built from the C language source code file
+ * previously generated by the rte_swx_pipeline_codegen() API function.
  *
  * @param[in] p
  *   Pipeline handle.
- * @param[in] spec
- *   Pipeline specification file.
- * @param[out] err_line
- *   In case of error and non-NULL, the line number within the *spec* file where
- *   the error occurred. The first line number in the file is 1.
- * @param[out] err_msg
- *   In case of error and non-NULL, the error message.
+ * @param[in] lib_file_name
+ *   Shared object library file name.
  * @return
  *   0 on success or the following error codes otherwise:
  *   -EINVAL: Invalid argument;
  *   -ENOMEM: Not enough space/cannot allocate memory;
- *   -EEXIST: Resource with the same name already exists;
+ *   -EEXIST: Pipeline was already built successfully;
  *   -ENODEV: Extern object or table creation error.
  */
 __rte_experimental
 int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg);
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline *p,
+				const char *lib_file_name);
 
 /**
  * Pipeline run
diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 05cf952816..206b514856 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -3514,54 +3514,3 @@ pipeline_spec_configure(struct rte_swx_pipeline *p,
 
 	return 0;
 }
-
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec_file,
-				 uint32_t *err_line,
-				 const char **err_msg)
-{
-	struct pipeline_spec *s = NULL;
-	int status = 0;
-
-	/* Check the input arguments. */
-	if (!p || !spec_file) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Invalid input argument.";
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Spec file parse. */
-	s = pipeline_spec_parse(spec_file, err_line, err_msg);
-	if (!s) {
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Pipeline configure. */
-	status = pipeline_spec_configure(p, s, err_msg);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		goto error;
-	}
-
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
-
-error:
-	pipeline_spec_free(s);
-	return status;
-}
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 51165d48cf..810cc56467 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -82,7 +82,6 @@ EXPERIMENTAL {
 	rte_swx_ctl_table_ops_get;
 	rte_swx_pipeline_action_config;
 	rte_swx_pipeline_build;
-	rte_swx_pipeline_build_from_spec;
 	rte_swx_pipeline_config;
 	rte_swx_pipeline_extern_func_register;
 	rte_swx_pipeline_extern_object_config;
@@ -148,4 +147,5 @@ EXPERIMENTAL {
 
 	#added in 22.11
 	rte_swx_pipeline_codegen;
+	rte_swx_pipeline_build_from_lib;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH 7/9] examples/pipeline: add CLI command for pipeline code generation
  2022-07-18 13:07 [PATCH 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                   ` (4 preceding siblings ...)
  2022-07-18 13:07 ` [PATCH 6/9] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
@ 2022-07-18 13:07 ` Cristian Dumitrescu
  2022-07-18 13:07 ` [PATCH 8/9] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:07 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the pipeline code generation operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 61 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 1f75b5dc9d..fdaf5dd16b 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -983,6 +983,53 @@ cmd_pipeline_port_out(char **tokens,
 	}
 }
 
+static const char cmd_pipeline_codegen_help[] =
+"pipeline codegen <spec_file> <code_file>\n";
+
+static void
+cmd_pipeline_codegen(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	FILE *spec_file = NULL;
+	FILE *code_file = NULL;
+	uint32_t err_line;
+	const char *err_msg;
+	int status;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	spec_file = fopen(tokens[2], "r");
+	if (!spec_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[2]);
+		return;
+	}
+
+	code_file = fopen(tokens[3], "w");
+	if (!code_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
+		return;
+	}
+
+	status = rte_swx_pipeline_codegen(spec_file,
+					  code_file,
+					  &err_line,
+					  &err_msg);
+
+	fclose(spec_file);
+	fclose(code_file);
+
+	if (status) {
+		snprintf(out, out_size, "Error %d at line %u: %s\n.",
+			status, err_line, err_msg);
+		return;
+	}
+}
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build <lib_file>\n";
 
@@ -2962,6 +3009,7 @@ cmd_help(char **tokens,
 			"\tpipeline create\n"
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
+			"\tpipeline codegen\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3031,6 +3079,12 @@ cmd_help(char **tokens,
 		}
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3309,6 +3363,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "codegen") == 0)) {
+			cmd_pipeline_codegen(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH 8/9] examples/pipeline: add CLI command for shared library build
  2022-07-18 13:07 [PATCH 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                   ` (5 preceding siblings ...)
  2022-07-18 13:07 ` [PATCH 7/9] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
@ 2022-07-18 13:07 ` Cristian Dumitrescu
  2022-07-18 13:07 ` [PATCH 9/9] examples/pipeline: call CLI commands for code generation and build Cristian Dumitrescu
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:07 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the shared object library build operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 147 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 143 insertions(+), 4 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index fdaf5dd16b..f1d2fbf52d 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -6,6 +6,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_ethdev.h>
@@ -25,6 +26,10 @@
 #define CMD_MAX_TOKENS     256
 #endif
 
+#ifndef MAX_LINE_SIZE
+#define MAX_LINE_SIZE 2048
+#endif
+
 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
@@ -1030,6 +1035,130 @@ cmd_pipeline_codegen(char **tokens,
 		return;
 	}
 }
+
+static const char cmd_pipeline_libbuild_help[] =
+"pipeline libbuild <code_file> <lib_file>\n";
+
+static void
+cmd_pipeline_libbuild(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	char *code_file, *lib_file, *obj_file = NULL, *log_file = NULL;
+	char *install_dir, *buffer = NULL;
+	size_t length;
+	int status = 0;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		goto free;
+	}
+
+	install_dir = getenv("RTE_INSTALL_DIR");
+	if (!install_dir) {
+		snprintf(out, out_size, "Error: Environment variable RTE_INSTALL_DIR is not set.");
+		return;
+	}
+
+	snprintf(out, out_size, "Using DPDK source code from \"%s\".\n", install_dir);
+	out_size -= strlen(out);
+	out += strlen(out);
+
+	code_file = tokens[2];
+	length = strnlen(code_file, MAX_LINE_SIZE);
+	if ((length < 3) ||
+	    (code_file[length - 2] != '.') ||
+	    (code_file[length - 1] != 'c')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "code_file");
+		goto free;
+	}
+
+	lib_file = tokens[3];
+	length = strnlen(lib_file, MAX_LINE_SIZE);
+	if ((length < 4) ||
+	    (lib_file[length - 3] != '.') ||
+	    (lib_file[length - 2] != 's') ||
+	    (lib_file[length - 1] != 'o')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "lib_file");
+		goto free;
+	}
+
+	obj_file = malloc(length);
+	log_file = malloc(length + 2);
+	if (!obj_file || !log_file) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		goto free;
+	}
+
+	memcpy(obj_file, lib_file, length - 2);
+	obj_file[length - 2] = 'o';
+	obj_file[length - 1] = 0;
+
+	memcpy(log_file, lib_file, length - 2);
+	log_file[length - 2] = 'l';
+	log_file[length - 1] = 'o';
+	log_file[length] = 'g';
+	log_file[length + 1] = 0;
+
+	buffer = malloc(MAX_LINE_SIZE);
+	if (!buffer) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		return;
+	}
+
+	snprintf(buffer,
+		 MAX_LINE_SIZE,
+		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s %s "
+		 "-I %s/lib/pipeline "
+		 "-I %s/lib/eal/include "
+		 "-I %s/lib/eal/x86/include "
+		 "-I %s/lib/eal/include/generic "
+		 "-I %s/lib/meter "
+		 "-I %s/lib/port "
+		 "-I %s/lib/table "
+		 "-I %s/lib/pipeline "
+		 "-I %s/config "
+		 "-I %s/build "
+		 "-I %s/lib/eal/linux/include "
+		 ">%s 2>&1 "
+		 "&& "
+		 "gcc -shared %s -o %s "
+		 ">>%s 2>&1",
+		 obj_file,
+		 code_file,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 log_file,
+		 obj_file,
+		 lib_file,
+		 log_file);
+
+	status = system(buffer);
+	if (status) {
+		snprintf(out,
+			 out_size,
+			 "Library build failed, see file \"%s\" for details.\n",
+			 log_file);
+		goto free;
+	}
+
+free:
+	free(obj_file);
+	free(log_file);
+	free(buffer);
+}
+
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build <lib_file>\n";
 
@@ -1080,10 +1209,6 @@ table_entry_free(struct rte_swx_table_entry *entry)
 	free(entry);
 }
 
-#ifndef MAX_LINE_SIZE
-#define MAX_LINE_SIZE 2048
-#endif
-
 static int
 pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p,
 			   const char *table_name,
@@ -3010,6 +3135,7 @@ cmd_help(char **tokens,
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
+			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3085,6 +3211,12 @@ cmd_help(char **tokens,
 		return;
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "libbuild") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_libbuild_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3370,6 +3502,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "libbuild") == 0)) {
+			cmd_pipeline_libbuild(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH 9/9] examples/pipeline: call CLI commands for code generation and build
  2022-07-18 13:07 [PATCH 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                   ` (6 preceding siblings ...)
  2022-07-18 13:07 ` [PATCH 8/9] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
@ 2022-07-18 13:07 ` Cristian Dumitrescu
  2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
  9 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:07 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Update the example CLI scripts with the commands for code generation
and shared object library build.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/examples/fib.cli               | 8 +++++++-
 examples/pipeline/examples/hash_func.cli         | 8 +++++++-
 examples/pipeline/examples/l2fwd.cli             | 8 +++++++-
 examples/pipeline/examples/l2fwd_macswp.cli      | 8 +++++++-
 examples/pipeline/examples/l2fwd_macswp_pcap.cli | 8 +++++++-
 examples/pipeline/examples/l2fwd_pcap.cli        | 8 +++++++-
 examples/pipeline/examples/learner.cli           | 8 +++++++-
 examples/pipeline/examples/meter.cli             | 8 +++++++-
 examples/pipeline/examples/mirroring.cli         | 8 +++++++-
 examples/pipeline/examples/recirculation.cli     | 8 +++++++-
 examples/pipeline/examples/registers.cli         | 8 +++++++-
 examples/pipeline/examples/selector.cli          | 8 +++++++-
 examples/pipeline/examples/varbit.cli            | 8 +++++++-
 examples/pipeline/examples/vxlan.cli             | 8 +++++++-
 examples/pipeline/examples/vxlan_pcap.cli        | 8 +++++++-
 15 files changed, 105 insertions(+), 15 deletions(-)

diff --git a/examples/pipeline/examples/fib.cli b/examples/pipeline/examples/fib.cli
index 93ab2b08f8..8b55175bf3 100644
--- a/examples/pipeline/examples/fib.cli
+++ b/examples/pipeline/examples/fib.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/fib.spec /tmp/fib.c
+pipeline libbuild /tmp/fib.c /tmp/fib.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -26,7 +32,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/fib.spec
+pipeline PIPELINE0 build /tmp/fib.so
 
 ;
 ; Initial set of table entries.
diff --git a/examples/pipeline/examples/hash_func.cli b/examples/pipeline/examples/hash_func.cli
index d65cd62d17..f7bb28b28b 100644
--- a/examples/pipeline/examples/hash_func.cli
+++ b/examples/pipeline/examples/hash_func.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/hash_func.spec /tmp/hash_func.c
+pipeline libbuild /tmp/hash_func.c /tmp/hash_func.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -26,7 +32,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/hash_func.spec
+pipeline PIPELINE0 build /tmp/hash_func.so
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/l2fwd.cli b/examples/pipeline/examples/l2fwd.cli
index d89caf2d0a..a71727309b 100644
--- a/examples/pipeline/examples/l2fwd.cli
+++ b/examples/pipeline/examples/l2fwd.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -20,6 +26,6 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+pipeline PIPELINE0 build /tmp/l2fwd.so
 
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp.cli b/examples/pipeline/examples/l2fwd_macswp.cli
index 0f2a89ac5b..d8f5f9f735 100644
--- a/examples/pipeline/examples/l2fwd_macswp.cli
+++ b/examples/pipeline/examples/l2fwd_macswp.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -20,6 +26,6 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+pipeline PIPELINE0 build /tmp/l2fwd_macswp.so
 
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp_pcap.cli b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
index e9656fe3c2..bd077876ff 100644
--- a/examples/pipeline/examples/l2fwd_macswp_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 pipeline PIPELINE0 create 0
@@ -15,6 +21,6 @@ pipeline PIPELINE0 port out 1 sink none
 pipeline PIPELINE0 port out 2 sink none
 pipeline PIPELINE0 port out 3 sink none
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+pipeline PIPELINE0 build /tmp/l2fwd_macswp.so
 
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_pcap.cli b/examples/pipeline/examples/l2fwd_pcap.cli
index 23fcb199f1..2e56a116af 100644
--- a/examples/pipeline/examples/l2fwd_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_pcap.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 pipeline PIPELINE0 create 0
@@ -15,6 +21,6 @@ pipeline PIPELINE0 port out 1 sink none
 pipeline PIPELINE0 port out 2 sink none
 pipeline PIPELINE0 port out 3 sink none
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+pipeline PIPELINE0 build /tmp/l2fwd.so
 
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/learner.cli b/examples/pipeline/examples/learner.cli
index 688ce34f34..10eb2af417 100644
--- a/examples/pipeline/examples/learner.cli
+++ b/examples/pipeline/examples/learner.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/learner.spec /tmp/learner.c
+pipeline libbuild /tmp/learner.c /tmp/learner.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -26,7 +32,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/learner.spec
+pipeline PIPELINE0 build /tmp/learner.so
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/meter.cli b/examples/pipeline/examples/meter.cli
index b29ed24022..9c22014f46 100644
--- a/examples/pipeline/examples/meter.cli
+++ b/examples/pipeline/examples/meter.cli
@@ -4,6 +4,12 @@
 ; Example command line:
 ;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/meter.cli
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/meter.spec /tmp/meter.c
+pipeline libbuild /tmp/meter.c /tmp/meter.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -23,7 +29,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/meter.spec
+pipeline PIPELINE0 build /tmp/meter.so
 
 pipeline PIPELINE0 meter profile platinum add cir 46000000 pir 138000000 cbs 1000000 pbs 1000000
 pipeline PIPELINE0 meter meters from 0 to 15 set profile platinum
diff --git a/examples/pipeline/examples/mirroring.cli b/examples/pipeline/examples/mirroring.cli
index 46d57db4ec..9614f64d38 100644
--- a/examples/pipeline/examples/mirroring.cli
+++ b/examples/pipeline/examples/mirroring.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/mirroring.spec /tmp/mirroring.c
+pipeline libbuild /tmp/mirroring.c /tmp/mirroring.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -27,7 +33,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/mirroring.spec
+pipeline PIPELINE0 build /tmp/mirroring.so
 
 ;
 ; Packet mirroring sessions.
diff --git a/examples/pipeline/examples/recirculation.cli b/examples/pipeline/examples/recirculation.cli
index f855c5c327..bd114e91cd 100644
--- a/examples/pipeline/examples/recirculation.cli
+++ b/examples/pipeline/examples/recirculation.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/recirculation.spec /tmp/recirculation.c
+pipeline libbuild /tmp/recirculation.c /tmp/recirculation.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -26,7 +32,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/recirculation.spec
+pipeline PIPELINE0 build /tmp/recirculation.so
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/registers.cli b/examples/pipeline/examples/registers.cli
index 8d026294cb..3d9eeb0d5c 100644
--- a/examples/pipeline/examples/registers.cli
+++ b/examples/pipeline/examples/registers.cli
@@ -4,6 +4,12 @@
 ; Example command line:
 ;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/registers.cli
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/registers.spec /tmp/registers.c
+pipeline libbuild /tmp/registers.c /tmp/registers.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -23,6 +29,6 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/registers.spec
+pipeline PIPELINE0 build /tmp/registers.so
 
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/selector.cli b/examples/pipeline/examples/selector.cli
index 123782c57b..6c7d032b10 100644
--- a/examples/pipeline/examples/selector.cli
+++ b/examples/pipeline/examples/selector.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/selector.spec /tmp/selector.c
+pipeline libbuild /tmp/selector.c /tmp/selector.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -20,7 +26,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/selector.spec
+pipeline PIPELINE0 build /tmp/selector.so
 
 pipeline PIPELINE0 selector s group add
 pipeline PIPELINE0 selector s group member add ./examples/pipeline/examples/selector.txt
diff --git a/examples/pipeline/examples/varbit.cli b/examples/pipeline/examples/varbit.cli
index 9caeb9ca26..545cde262e 100644
--- a/examples/pipeline/examples/varbit.cli
+++ b/examples/pipeline/examples/varbit.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/varbit.spec /tmp/varbit.c
+pipeline libbuild /tmp/varbit.c /tmp/varbit.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -26,7 +32,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/varbit.spec
+pipeline PIPELINE0 build /tmp/varbit.so
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/vxlan.cli b/examples/pipeline/examples/vxlan.cli
index 444f3f7bd8..321a28ba44 100644
--- a/examples/pipeline/examples/vxlan.cli
+++ b/examples/pipeline/examples/vxlan.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -20,7 +26,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+pipeline PIPELINE0 build /tmp/vxlan.so
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
diff --git a/examples/pipeline/examples/vxlan_pcap.cli b/examples/pipeline/examples/vxlan_pcap.cli
index 83fca8d0d9..596169f933 100644
--- a/examples/pipeline/examples/vxlan_pcap.cli
+++ b/examples/pipeline/examples/vxlan_pcap.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 pipeline PIPELINE0 create 0
@@ -15,7 +21,7 @@ pipeline PIPELINE0 port out 1 sink none
 pipeline PIPELINE0 port out 2 sink none
 pipeline PIPELINE0 port out 3 sink none
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+pipeline PIPELINE0 build /tmp/vxlan.so
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V2 1/9] pipeline: move specification data structures to internal header
  2022-07-18 13:07 [PATCH 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                   ` (7 preceding siblings ...)
  2022-07-18 13:07 ` [PATCH 9/9] examples/pipeline: call CLI commands for code generation and build Cristian Dumitrescu
@ 2022-07-18 13:25 ` Cristian Dumitrescu
  2022-07-18 13:25   ` [PATCH V2 2/9] pipeline: add pipeline specification data structure Cristian Dumitrescu
                     ` (8 more replies)
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
  9 siblings, 9 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:25 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Move all the pipeline object specification data structures to an
internal header file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 126 +------------------
 lib/pipeline/rte_swx_pipeline_spec.h | 176 +++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 125 deletions(-)
 create mode 100644 lib/pipeline/rte_swx_pipeline_spec.h

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 904b9eb471..5e07b4f794 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -9,7 +9,7 @@
 
 #include <rte_common.h>
 
-#include "rte_swx_pipeline.h"
+#include "rte_swx_pipeline_spec.h"
 
 #ifndef MAX_LINE_LENGTH
 #define MAX_LINE_LENGTH 2048
@@ -34,15 +34,7 @@
 
 /*
  * extobj.
- *
- * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
  */
-struct extobj_spec {
-	char *name;
-	char *extern_type_name;
-	char *pragma;
-};
-
 static void
 extobj_spec_free(struct extobj_spec *s)
 {
@@ -104,18 +96,7 @@ extobj_statement_parse(struct extobj_spec *s,
 /*
  * struct.
  *
- * struct STRUCT_TYPE_NAME {
- *	bit<SIZE> | varbit<SIZE> FIELD_NAME
- *	...
- * }
  */
-struct struct_spec {
-	char *name;
-	struct rte_swx_field_params *fields;
-	uint32_t n_fields;
-	int varbit;
-};
-
 static void
 struct_spec_free(struct struct_spec *s)
 {
@@ -293,13 +274,7 @@ struct_block_parse(struct struct_spec *s,
 /*
  * header.
  *
- * header HEADER_NAME instanceof STRUCT_TYPE_NAME
  */
-struct header_spec {
-	char *name;
-	char *struct_type_name;
-};
-
 static void
 header_spec_free(struct header_spec *s)
 {
@@ -351,12 +326,7 @@ header_statement_parse(struct header_spec *s,
 /*
  * metadata.
  *
- * metadata instanceof STRUCT_TYPE_NAME
  */
-struct metadata_spec {
-	char *struct_type_name;
-};
-
 static void
 metadata_spec_free(struct metadata_spec *s)
 {
@@ -400,18 +370,7 @@ metadata_statement_parse(struct metadata_spec *s,
 /*
  * action.
  *
- * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
- *	INSTRUCTION
- *	...
- * }
  */
-struct action_spec {
-	char *name;
-	char *args_struct_type_name;
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 action_spec_free(struct action_spec *s)
 {
@@ -540,29 +499,7 @@ action_block_parse(struct action_spec *s,
 /*
  * table.
  *
- * table TABLE_NAME {
- *	key {
- *		MATCH_FIELD_NAME exact | wildcard | lpm
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly ]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	instanceof TABLE_TYPE_NAME
- *	pragma ARGS
- *	size SIZE
- * }
  */
-struct table_spec {
-	char *name;
-	struct rte_swx_pipeline_table_params params;
-	char *recommended_table_type_name;
-	char *args;
-	uint32_t size;
-};
-
 static void
 table_spec_free(struct table_spec *s)
 {
@@ -1084,22 +1021,7 @@ table_block_parse(struct table_spec *s,
 /*
  * selector.
  *
- * selector SELECTOR_NAME {
- *	group_id FIELD_NAME
- *	selector {
- *		FIELD_NAME
- *		...
- *	}
- *	member_id FIELD_NAME
- *	n_groups N_GROUPS
- *	n_members_per_group N_MEMBERS_PER_GROUP
- * }
  */
-struct selector_spec {
-	char *name;
-	struct rte_swx_pipeline_selector_params params;
-};
-
 static void
 selector_spec_free(struct selector_spec *s)
 {
@@ -1385,31 +1307,7 @@ selector_block_parse(struct selector_spec *s,
 /*
  * learner.
  *
- * learner LEARNER_NAME {
- *	key {
- *		MATCH_FIELD_NAME
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	size SIZE
- *	timeout {
- *		TIMEOUT_IN_SECONDS
- *		...
- *	}
- * }
  */
-struct learner_spec {
-	char *name;
-	struct rte_swx_pipeline_learner_params params;
-	uint32_t size;
-	uint32_t *timeout;
-	uint32_t n_timeouts;
-};
-
 static void
 learner_spec_free(struct learner_spec *s)
 {
@@ -1958,14 +1856,7 @@ learner_block_parse(struct learner_spec *s,
 /*
  * regarray.
  *
- * regarray NAME size SIZE initval INITVAL
  */
-struct regarray_spec {
-	char *name;
-	uint64_t init_val;
-	uint32_t size;
-};
-
 static void
 regarray_spec_free(struct regarray_spec *s)
 {
@@ -2033,13 +1924,7 @@ regarray_statement_parse(struct regarray_spec *s,
 /*
  * metarray.
  *
- * metarray NAME size SIZE
  */
-struct metarray_spec {
-	char *name;
-	uint32_t size;
-};
-
 static void
 metarray_spec_free(struct metarray_spec *s)
 {
@@ -2095,16 +1980,7 @@ metarray_statement_parse(struct metarray_spec *s,
 /*
  * apply.
  *
- * apply {
- *	INSTRUCTION
- *	...
- * }
  */
-struct apply_spec {
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 apply_spec_free(struct apply_spec *s)
 {
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
new file mode 100644
index 0000000000..8458de878a
--- /dev/null
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Intel Corporation
+ */
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_common.h>
+
+#include <rte_swx_pipeline.h>
+
+/*
+ * extobj.
+ *
+ * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
+ */
+struct extobj_spec {
+	char *name;
+	char *extern_type_name;
+	char *pragma;
+};
+
+/*
+ * struct.
+ *
+ * struct STRUCT_TYPE_NAME {
+ *	bit<SIZE> | varbit<SIZE> FIELD_NAME
+ *	...
+ * }
+ */
+struct struct_spec {
+	char *name;
+	struct rte_swx_field_params *fields;
+	uint32_t n_fields;
+	int varbit;
+};
+
+/*
+ * header.
+ *
+ * header HEADER_NAME instanceof STRUCT_TYPE_NAME
+ */
+struct header_spec {
+	char *name;
+	char *struct_type_name;
+};
+
+/*
+ * metadata.
+ *
+ * metadata instanceof STRUCT_TYPE_NAME
+ */
+struct metadata_spec {
+	char *struct_type_name;
+};
+
+/*
+ * action.
+ *
+ * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct action_spec {
+	char *name;
+	char *args_struct_type_name;
+	const char **instructions;
+	uint32_t n_instructions;
+};
+
+/*
+ * table.
+ *
+ * table TABLE_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME exact | wildcard | lpm
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly ]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	instanceof TABLE_TYPE_NAME
+ *	pragma ARGS
+ *	size SIZE
+ * }
+ */
+struct table_spec {
+	char *name;
+	struct rte_swx_pipeline_table_params params;
+	char *recommended_table_type_name;
+	char *args;
+	uint32_t size;
+};
+
+/*
+ * selector.
+ *
+ * selector SELECTOR_NAME {
+ *	group_id FIELD_NAME
+ *	selector {
+ *		FIELD_NAME
+ *		...
+ *	}
+ *	member_id FIELD_NAME
+ *	n_groups N_GROUPS
+ *	n_members_per_group N_MEMBERS_PER_GROUP
+ * }
+ */
+struct selector_spec {
+	char *name;
+	struct rte_swx_pipeline_selector_params params;
+};
+
+/*
+ * learner.
+ *
+ * learner LEARNER_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	size SIZE
+ *	timeout {
+ *		TIMEOUT_IN_SECONDS
+ *		...
+ *	}
+ * }
+ */
+struct learner_spec {
+	char *name;
+	struct rte_swx_pipeline_learner_params params;
+	uint32_t size;
+	uint32_t *timeout;
+	uint32_t n_timeouts;
+};
+
+/*
+ * regarray.
+ *
+ * regarray NAME size SIZE initval INITVAL
+ */
+struct regarray_spec {
+	char *name;
+	uint64_t init_val;
+	uint32_t size;
+};
+
+/*
+ * metarray.
+ *
+ * metarray NAME size SIZE
+ */
+struct metarray_spec {
+	char *name;
+	uint32_t size;
+};
+
+/*
+ * apply.
+ *
+ * apply {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct apply_spec {
+	const char **instructions;
+	uint32_t n_instructions;
+};
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V2 2/9] pipeline: add pipeline specification data structure
  2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
@ 2022-07-18 13:25   ` Cristian Dumitrescu
  2022-07-18 13:25   ` [PATCH V2 3/9] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:25 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add specification data structure for the entire pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 21 ++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h | 32 ++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 5e07b4f794..642091b678 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2082,6 +2082,27 @@ apply_block_parse(struct apply_spec *s,
 /*
  * Pipeline.
  */
+void
+pipeline_spec_free(struct pipeline_spec *s)
+{
+	if (!s)
+		return;
+
+	free(s->extobjs);
+	free(s->structs);
+	free(s->headers);
+	free(s->metadata);
+	free(s->actions);
+	free(s->tables);
+	free(s->selectors);
+	free(s->learners);
+	free(s->regarrays);
+	free(s->metarrays);
+	free(s->apply);
+
+	memset(s, 0, sizeof(struct pipeline_spec));
+}
+
 int
 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				 FILE *spec,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 8458de878a..e1170a33b1 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -174,3 +174,35 @@ struct apply_spec {
 	const char **instructions;
 	uint32_t n_instructions;
 };
+
+/*
+ * Pipeline.
+ */
+struct pipeline_spec {
+	struct extobj_spec *extobjs;
+	struct struct_spec *structs;
+	struct header_spec *headers;
+	struct metadata_spec *metadata;
+	struct action_spec *actions;
+	struct table_spec *tables;
+	struct selector_spec *selectors;
+	struct learner_spec *learners;
+	struct regarray_spec *regarrays;
+	struct metarray_spec *metarrays;
+	struct apply_spec *apply;
+
+	uint32_t n_extobjs;
+	uint32_t n_structs;
+	uint32_t n_headers;
+	uint32_t n_metadata;
+	uint32_t n_actions;
+	uint32_t n_tables;
+	uint32_t n_selectors;
+	uint32_t n_learners;
+	uint32_t n_regarrays;
+	uint32_t n_metarrays;
+	uint32_t n_apply;
+};
+
+void
+pipeline_spec_free(struct pipeline_spec *s);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V2 3/9] pipeline: rework the specification file-based pipeline build
  2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
  2022-07-18 13:25   ` [PATCH V2 2/9] pipeline: add pipeline specification data structure Cristian Dumitrescu
@ 2022-07-18 13:25   ` Cristian Dumitrescu
  2022-07-18 13:25   ` [PATCH V2 4/9] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:25 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Rework the specification file-based pipeline build operation to first
parse the specification file into the previously introduced pipeline
specification data structure, then use this structure to configure
and build the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 478 +++++++++++++++++++++------
 lib/pipeline/rte_swx_pipeline_spec.h |   9 +
 2 files changed, 385 insertions(+), 102 deletions(-)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 642091b678..62929a9da6 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2103,11 +2103,10 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg)
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg)
 {
 	struct extobj_spec extobj_spec = {0};
 	struct struct_spec struct_spec = {0};
@@ -2120,26 +2119,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	struct regarray_spec regarray_spec = {0};
 	struct metarray_spec metarray_spec = {0};
 	struct apply_spec apply_spec = {0};
-	uint32_t n_lines;
+	struct pipeline_spec *s = NULL;
+	uint32_t n_lines = 0;
 	uint32_t block_mask = 0;
-	int status;
+	int status = 0;
 
 	/* Check the input arguments. */
-	if (!p) {
+	if (!spec) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null pipeline argument.";
+			*err_msg = "Invalid input argument.";
 		status = -EINVAL;
 		goto error;
 	}
 
-	if (!spec) {
+	/* Memory allocation. */
+	s = calloc(sizeof(struct pipeline_spec), 1);
+	if (!s) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null specification file argument.";
-		status = -EINVAL;
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
 		goto error;
 	}
 
@@ -2200,6 +2202,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* struct block. */
 		if (block_mask & (1 << STRUCT_BLOCK)) {
+			struct struct_spec *new_structs;
+
 			status = struct_block_parse(&struct_spec,
 						    &block_mask,
 						    tokens,
@@ -2214,26 +2218,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_struct_type_register(p,
-				struct_spec.name,
-				struct_spec.fields,
-				struct_spec.n_fields,
-				struct_spec.varbit);
-			if (status) {
+			new_structs = realloc(s->structs,
+					      (s->n_structs + 1) * sizeof(struct struct_spec));
+			if (!new_structs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Struct registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			struct_spec_free(&struct_spec);
+			s->structs = new_structs;
+			memcpy(&s->structs[s->n_structs], &struct_spec, sizeof(struct struct_spec));
+			s->n_structs++;
+			memset(&struct_spec, 0, sizeof(struct struct_spec));
 
 			continue;
 		}
 
 		/* action block. */
 		if (block_mask & (1 << ACTION_BLOCK)) {
+			struct action_spec *new_actions;
+
 			status = action_block_parse(&action_spec,
 						    &block_mask,
 						    tokens,
@@ -2248,26 +2255,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_action_config(p,
-				action_spec.name,
-				action_spec.args_struct_type_name,
-				action_spec.instructions,
-				action_spec.n_instructions);
-			if (status) {
+			new_actions = realloc(s->actions,
+					      (s->n_actions + 1) * sizeof(struct action_spec));
+			if (!new_actions) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Action config error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			action_spec_free(&action_spec);
+			s->actions = new_actions;
+			memcpy(&s->actions[s->n_actions], &action_spec, sizeof(struct action_spec));
+			s->n_actions++;
+			memset(&action_spec, 0, sizeof(struct action_spec));
 
 			continue;
 		}
 
 		/* table block. */
 		if (block_mask & (1 << TABLE_BLOCK)) {
+			struct table_spec *new_tables;
+
 			status = table_block_parse(&table_spec,
 						   &block_mask,
 						   tokens,
@@ -2282,27 +2292,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_table_config(p,
-				table_spec.name,
-				&table_spec.params,
-				table_spec.recommended_table_type_name,
-				table_spec.args,
-				table_spec.size);
-			if (status) {
+			new_tables = realloc(s->tables,
+					     (s->n_tables + 1) * sizeof(struct table_spec));
+			if (!new_tables) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			table_spec_free(&table_spec);
+			s->tables = new_tables;
+			memcpy(&s->tables[s->n_tables], &table_spec, sizeof(struct table_spec));
+			s->n_tables++;
+			memset(&table_spec, 0, sizeof(struct table_spec));
 
 			continue;
 		}
 
 		/* selector block. */
 		if (block_mask & (1 << SELECTOR_BLOCK)) {
+			struct selector_spec *new_selectors;
+
 			status = selector_block_parse(&selector_spec,
 						      &block_mask,
 						      tokens,
@@ -2317,24 +2329,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_selector_config(p,
-				selector_spec.name,
-				&selector_spec.params);
-			if (status) {
+			new_selectors = realloc(s->selectors,
+				(s->n_selectors + 1) * sizeof(struct selector_spec));
+			if (!new_selectors) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Selector configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			selector_spec_free(&selector_spec);
+			s->selectors = new_selectors;
+			memcpy(&s->selectors[s->n_selectors],
+			       &selector_spec,
+			       sizeof(struct selector_spec));
+			s->n_selectors++;
+			memset(&selector_spec, 0, sizeof(struct selector_spec));
 
 			continue;
 		}
 
 		/* learner block. */
 		if (block_mask & (1 << LEARNER_BLOCK)) {
+			struct learner_spec *new_learners;
+
 			status = learner_block_parse(&learner_spec,
 						     &block_mask,
 						     tokens,
@@ -2349,27 +2368,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_learner_config(p,
-				learner_spec.name,
-				&learner_spec.params,
-				learner_spec.size,
-				learner_spec.timeout,
-				learner_spec.n_timeouts);
-			if (status) {
+			new_learners = realloc(s->learners,
+					       (s->n_learners + 1) * sizeof(struct learner_spec));
+			if (!new_learners) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Learner table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			learner_spec_free(&learner_spec);
+			s->learners = new_learners;
+			memcpy(&s->learners[s->n_learners],
+			       &learner_spec,
+			       sizeof(struct learner_spec));
+			s->n_learners++;
+			memset(&learner_spec, 0, sizeof(struct learner_spec));
 
 			continue;
 		}
 
 		/* apply block. */
 		if (block_mask & (1 << APPLY_BLOCK)) {
+			struct apply_spec *new_apply;
+
 			status = apply_block_parse(&apply_spec,
 						   &block_mask,
 						   tokens,
@@ -2384,24 +2407,28 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_instructions_config(p,
-				apply_spec.instructions,
-				apply_spec.n_instructions);
-			if (status) {
+			new_apply = realloc(s->apply, (s->n_apply + 1) * sizeof(struct apply_spec));
+			if (!new_apply) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Pipeline instructions err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			apply_spec_free(&apply_spec);
+			s->apply = new_apply;
+			memcpy(&s->apply[s->n_apply], &apply_spec, sizeof(struct apply_spec));
+			s->n_apply++;
+			memset(&apply_spec, 0, sizeof(struct apply_spec));
 
 			continue;
 		}
 
 		/* extobj. */
 		if (!strcmp(tokens[0], "extobj")) {
+			struct extobj_spec *new_extobjs;
+
 			status = extobj_statement_parse(&extobj_spec,
 							tokens,
 							n_tokens,
@@ -2411,19 +2438,21 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_extern_object_config(p,
-				extobj_spec.name,
-				extobj_spec.extern_type_name,
-				extobj_spec.pragma);
-			if (status) {
+			new_extobjs = realloc(s->extobjs,
+					      (s->n_extobjs + 1) * sizeof(struct extobj_spec));
+			if (!new_extobjs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Extern object config err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			extobj_spec_free(&extobj_spec);
+			s->extobjs = new_extobjs;
+			memcpy(&s->extobjs[s->n_extobjs], &extobj_spec, sizeof(struct extobj_spec));
+			s->n_extobjs++;
+			memset(&extobj_spec, 0, sizeof(struct extobj_spec));
 
 			continue;
 		}
@@ -2445,6 +2474,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* header. */
 		if (!strcmp(tokens[0], "header")) {
+			struct header_spec *new_headers;
+
 			status = header_statement_parse(&header_spec,
 							tokens,
 							n_tokens,
@@ -2454,24 +2485,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_header_register(p,
-				header_spec.name,
-				header_spec.struct_type_name);
-			if (status) {
+			new_headers = realloc(s->headers,
+					      (s->n_headers + 1) * sizeof(struct header_spec));
+			if (!new_headers) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Header registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			header_spec_free(&header_spec);
+			s->headers = new_headers;
+			memcpy(&s->headers[s->n_headers], &header_spec, sizeof(struct header_spec));
+			s->n_headers++;
+			memset(&header_spec, 0, sizeof(struct header_spec));
 
 			continue;
 		}
 
 		/* metadata. */
 		if (!strcmp(tokens[0], "metadata")) {
+			struct metadata_spec *new_metadata;
+
 			status = metadata_statement_parse(&metadata_spec,
 							  tokens,
 							  n_tokens,
@@ -2481,17 +2517,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_metadata_register(p,
-				metadata_spec.struct_type_name);
-			if (status) {
+			new_metadata = realloc(s->metadata,
+					       (s->n_metadata + 1) * sizeof(struct metadata_spec));
+			if (!new_metadata) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meta-data reg err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metadata_spec_free(&metadata_spec);
+			s->metadata = new_metadata;
+			memcpy(&s->metadata[s->n_metadata],
+			       &metadata_spec,
+			       sizeof(struct metadata_spec));
+			s->n_metadata++;
+			memset(&metadata_spec, 0, sizeof(struct metadata_spec));
 
 			continue;
 		}
@@ -2558,6 +2600,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* regarray. */
 		if (!strcmp(tokens[0], "regarray")) {
+			struct regarray_spec *new_regarrays;
+
 			status = regarray_statement_parse(&regarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2567,25 +2611,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_regarray_config(p,
-				regarray_spec.name,
-				regarray_spec.size,
-				regarray_spec.init_val);
-			if (status) {
+			new_regarrays = realloc(s->regarrays,
+				(s->n_regarrays + 1) * sizeof(struct regarray_spec));
+			if (!new_regarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Register array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			regarray_spec_free(&regarray_spec);
+			s->regarrays = new_regarrays;
+			memcpy(&s->regarrays[s->n_regarrays],
+			       &regarray_spec,
+			       sizeof(struct regarray_spec));
+			s->n_regarrays++;
+			memset(&regarray_spec, 0, sizeof(struct regarray_spec));
 
 			continue;
 		}
 
 		/* metarray. */
 		if (!strcmp(tokens[0], "metarray")) {
+			struct metarray_spec *new_metarrays;
+
 			status = metarray_statement_parse(&metarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2595,18 +2645,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_metarray_config(p,
-				metarray_spec.name,
-				metarray_spec.size);
-			if (status) {
+			new_metarrays = realloc(s->metarrays,
+				(s->n_metarrays + 1) * sizeof(struct metarray_spec));
+			if (!new_metarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meter array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metarray_spec_free(&metarray_spec);
+			s->metarrays = new_metarrays;
+			memcpy(&s->metarrays[s->n_metarrays],
+			       &metarray_spec,
+			       sizeof(struct metarray_spec));
+			s->n_metarrays++;
+			memset(&metarray_spec, 0, sizeof(struct metarray_spec));
 
 			continue;
 		}
@@ -2644,17 +2699,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 		goto error;
 	}
 
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = n_lines;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
+	return s;
 
 error:
 	extobj_spec_free(&extobj_spec);
@@ -2668,5 +2713,234 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	regarray_spec_free(&regarray_spec);
 	metarray_spec_free(&metarray_spec);
 	apply_spec_free(&apply_spec);
+	pipeline_spec_free(s);
+
+	return NULL;
+}
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg)
+{
+	uint32_t i;
+	int status = 0;
+
+	/* extobj. */
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		status = rte_swx_pipeline_extern_object_config(p,
+			extobj_spec->name,
+			extobj_spec->extern_type_name,
+			extobj_spec->pragma);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Extern object configuration error.";
+			return status;
+		}
+	}
+
+	/* regarray. */
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		status = rte_swx_pipeline_regarray_config(p,
+			regarray_spec->name,
+			regarray_spec->size,
+			regarray_spec->init_val);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Register array configuration error.";
+			return status;
+		}
+	}
+
+	/* metarray. */
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		status = rte_swx_pipeline_metarray_config(p,
+			metarray_spec->name,
+			metarray_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meter array configuration error.";
+			return status;
+		}
+	}
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		status = rte_swx_pipeline_struct_type_register(p,
+			struct_spec->name,
+			struct_spec->fields,
+			struct_spec->n_fields,
+			struct_spec->varbit);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Struct type registration error.";
+			return status;
+		}
+	}
+
+	/* header. */
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		status = rte_swx_pipeline_packet_header_register(p,
+			header_spec->name,
+			header_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Header configuration error.";
+			return status;
+		}
+	}
+
+	/* metadata. */
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		status = rte_swx_pipeline_packet_metadata_register(p,
+			metadata_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meta-data registration error.";
+			return status;
+		}
+	}
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		status = rte_swx_pipeline_action_config(p,
+			action_spec->name,
+			action_spec->args_struct_type_name,
+			action_spec->instructions,
+			action_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Action configuration error.";
+			return status;
+		}
+	}
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		status = rte_swx_pipeline_table_config(p,
+			table_spec->name,
+			&table_spec->params,
+			table_spec->recommended_table_type_name,
+			table_spec->args,
+			table_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Table configuration error.";
+			return status;
+		}
+	}
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		status = rte_swx_pipeline_selector_config(p,
+			selector_spec->name,
+			&selector_spec->params);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Selector table configuration error.";
+			return status;
+		}
+	}
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		status = rte_swx_pipeline_learner_config(p,
+			learner_spec->name,
+			&learner_spec->params,
+			learner_spec->size,
+			learner_spec->timeout,
+			learner_spec->n_timeouts);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Learner table configuration error.";
+			return status;
+		}
+	}
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+
+		status = rte_swx_pipeline_instructions_config(p,
+			apply_spec->instructions,
+			apply_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline instructions configuration error.";
+			return status;
+		}
+	}
+
+	return 0;
+}
+
+int
+rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
+				 FILE *spec_file,
+				 uint32_t *err_line,
+				 const char **err_msg)
+{
+	struct pipeline_spec *s = NULL;
+	int status = 0;
+
+	/* Check the input arguments. */
+	if (!p || !spec_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Spec file parse. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Pipeline configure. */
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto error;
+	}
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline build error.";
+		goto error;
+	}
+
+	return 0;
+
+error:
+	pipeline_spec_free(s);
 	return status;
 }
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index e1170a33b1..4f3a0b5958 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,3 +206,12 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg);
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V2 4/9] pipeline: generate the code for pipeline specification structure
  2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
  2022-07-18 13:25   ` [PATCH V2 2/9] pipeline: add pipeline specification data structure Cristian Dumitrescu
  2022-07-18 13:25   ` [PATCH V2 3/9] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
@ 2022-07-18 13:25   ` Cristian Dumitrescu
  2022-07-18 13:25   ` [PATCH V2 5/9] pipeline: add API for pipeline code generation Cristian Dumitrescu
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:25 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add support to export the pipeline specification data structure to a C
source code file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 622 +++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h |   5 +
 2 files changed, 627 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 62929a9da6..bf21fe17ba 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2020 Intel Corporation
  */
 #include <stdint.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -2103,6 +2104,627 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
+static const char *
+match_type_string_get(enum rte_swx_table_match_type match_type)
+{
+	switch (match_type) {
+	case RTE_SWX_TABLE_MATCH_WILDCARD: return "RTE_SWX_TABLE_MATCH_WILDCARD";
+	case RTE_SWX_TABLE_MATCH_LPM: return "RTE_SWX_TABLE_MATCH_LPM";
+	case RTE_SWX_TABLE_MATCH_EXACT: return "RTE_SWX_TABLE_MATCH_EXACT";
+	default: return "RTE_SWX_TABLE_MATCH_UNKNOWN";
+	}
+}
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s)
+{
+	uint32_t i;
+
+	/* Check the input arguments. */
+	if (!f || !s)
+		return;
+
+	/* extobj. */
+	fprintf(f, "static struct extobj_spec extobjs[] = {\n");
+
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", extobj_spec->name);
+		fprintf(f, "\t\t.extern_type_name = \"%s\",\n", extobj_spec->extern_type_name);
+		if (extobj_spec->pragma)
+			fprintf(f, "\t\t.pragma = \"%s\",\n", extobj_spec->pragma);
+		else
+			fprintf(f, "\t\t.pragma = NULL,\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* regarray. */
+	fprintf(f, "static struct regarray_spec regarrays[] = {\n");
+
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", regarray_spec->name);
+		fprintf(f, "\t\t.init_val = %" PRIu64 ",\n", regarray_spec->init_val);
+		fprintf(f, "\t\t.size = %u,\n", regarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metarray. */
+	fprintf(f, "static struct metarray_spec metarrays[] = {\n");
+
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", metarray_spec->name);
+		fprintf(f, "\t\t.size = %u,\n", metarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+		uint32_t j;
+
+		fprintf(f, "static struct rte_swx_field_params struct_%s_fields[] = {\n",
+			struct_spec->name);
+
+		for (j = 0; j < struct_spec->n_fields; j++) {
+			struct rte_swx_field_params *field = &struct_spec->fields[j];
+
+			fprintf(f, "\t[%d] = {\n", j);
+			fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+			fprintf(f, "\t\t.n_bits = %u,\n", field->n_bits);
+			fprintf(f, "\t},\n");
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct struct_spec structs[] = {\n");
+
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", struct_spec->name);
+		fprintf(f, "\t\t.fields = struct_%s_fields,\n", struct_spec->name);
+		fprintf(f, "\t\t.n_fields = "
+			"sizeof(struct_%s_fields) / sizeof(struct_%s_fields[0]),\n",
+			struct_spec->name,
+			struct_spec->name);
+		fprintf(f, "\t\t.varbit = %d,\n", struct_spec->varbit);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* header. */
+	fprintf(f, "static struct header_spec headers[] = {\n");
+
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", header_spec->name);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", header_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metadata. */
+	fprintf(f, "static struct metadata_spec metadata[] = {\n");
+
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", metadata_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *action_%s_initial_instructions[] = {\n",
+			action_spec->name);
+
+		for (j = 0; j < action_spec->n_instructions; j++) {
+			const char *instr = action_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct action_spec actions[] = {\n");
+
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", action_spec->name);
+
+		if (action_spec->args_struct_type_name)
+			fprintf(f, "\t\t.args_struct_type_name = \"%s\",\n",
+				action_spec->args_struct_type_name);
+		else
+			fprintf(f, "\t\t.args_struct_type_name = NULL,\n");
+
+		fprintf(f, "\t\t.instructions = action_%s_initial_instructions,\n",
+			action_spec->name);
+		fprintf(f, "\t\t.n_instructions = "
+			"sizeof(action_%s_initial_instructions) / "
+			"sizeof(action_%s_initial_instructions[0]),\n",
+			action_spec->name,
+			action_spec->name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+		uint32_t j;
+
+		/* fields. */
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "static struct rte_swx_match_field_params "
+				"table_%s_fields[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_fields; j++) {
+				struct rte_swx_match_field_params *field =
+					&table_spec->params.fields[j];
+
+				fprintf(f, "\t[%d] = {\n", j);
+				fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+				fprintf(f, "\t\t.match_type = %s,\n",
+					match_type_string_get(field->match_type));
+				fprintf(f, "\t},\n");
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (table_spec->params.action_names && table_spec->params.n_actions) {
+			fprintf(f, "static const char *table_%s_action_names[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				const char *action_name = table_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (table_spec->params.action_is_for_table_entries &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_table_entries[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (table_spec->params.action_is_for_default_entry &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_default_entry[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct table_spec tables[] = {\n");
+
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", table_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.fields = table_%s_fields,\n", table_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(table_%s_fields) / sizeof(table_%s_fields[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.fields = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (table_spec->params.action_names && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = table_%s_action_names,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (table_spec->params.action_is_for_table_entries && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"table_%s_action_is_for_table_entries,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (table_spec->params.action_is_for_default_entry && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"table_%s_action_is_for_default_entry,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = sizeof(table_%s_action_names) / "
+				"sizeof(table_%s_action_names[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = 0,\n");
+
+		if (table_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				table_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (table_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				table_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			table_spec->params.default_action_is_const);
+		fprintf(f, "\t\t},\n");
+
+		if (table_spec->recommended_table_type_name)
+			fprintf(f, "\t\t.recommended_table_type_name = \"%s\",\n",
+				table_spec->recommended_table_type_name);
+		else
+			fprintf(f, "\t\t.recommended_table_type_name = NULL,\n");
+
+		if (table_spec->args)
+			fprintf(f, "\t\t.args = \"%s\",\n", table_spec->args);
+		else
+			fprintf(f, "\t\t.args = NULL,\n");
+
+		fprintf(f, "\t\t.size = %u,\n", table_spec->size);
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+		uint32_t j;
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "static const char *selector_%s_field_names[] = {\n",
+				selector_spec->name);
+
+			for (j = 0; j < selector_spec->params.n_selector_fields; j++) {
+				const char *field_name =
+					selector_spec->params.selector_field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct selector_spec selectors[] = {\n");
+
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+
+		fprintf(f, "\t\t.name = \"%s\",\n", selector_spec->name);
+		fprintf(f, "\t\t.params = {\n");
+
+		if (selector_spec->params.group_id_field_name)
+			fprintf(f, "\t\t\t.group_id_field_name = \"%s\",\n",
+				selector_spec->params.group_id_field_name);
+		else
+			fprintf(f, "\t\t\t.group_id_field_name = NULL,\n");
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "\t\t\t.selector_field_names = selector_%s_field_names,\n",
+				selector_spec->name);
+			fprintf(f, "\t\t\t.n_selector_fields = "
+				"sizeof(selector_%s_field_names) / sizeof(selector_%s_field_names[0]),\n",
+				selector_spec->name,
+				selector_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.selector_field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_selector_fields = 0,\n");
+		}
+
+		if (selector_spec->params.member_id_field_name)
+			fprintf(f, "\t\t\t.member_id_field_name = \"%s\",\n",
+				selector_spec->params.member_id_field_name);
+		else
+			fprintf(f, "\t\t\t.member_id_field_name = NULL,\n");
+
+		fprintf(f, "\t\t\t.n_groups_max = %u,\n", selector_spec->params.n_groups_max);
+
+		fprintf(f, "\t\t\t.n_members_per_group_max = %u,\n",
+			selector_spec->params.n_members_per_group_max);
+
+		fprintf(f, "\t\t},\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+		uint32_t j;
+
+		/* field_names. */
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "static const char *learner_%s_field_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_fields; j++) {
+				const char *field_name = learner_spec->params.field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (learner_spec->params.action_names && learner_spec->params.n_actions) {
+			fprintf(f, "static const char *learner_%s_action_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				const char *action_name = learner_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_table_entries[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_default_entry[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* timeout. */
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "static uint32_t learner_%s_timeout[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->n_timeouts; j++) {
+				uint32_t value = learner_spec->timeout[j];
+
+				fprintf(f, "\t[%d] = %u,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct learner_spec learners[] = {\n");
+
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", learner_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.field_names = learner_%s_field_names,\n",
+				learner_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(learner_%s_field_names) / "
+				"sizeof(learner_%s_field_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = learner_%s_action_names,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"learner_%s_action_is_for_table_entries,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"learner_%s_action_is_for_default_entry,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = "
+				"sizeof(learner_%s_action_names) / sizeof(learner_%s_action_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = NULL,\n");
+
+		if (learner_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				learner_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (learner_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				learner_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			learner_spec->params.default_action_is_const);
+
+		fprintf(f, "\t\t},\n");
+
+		fprintf(f, "\t\t.size = %u,\n", learner_spec->size);
+
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "\t\t.timeout = learner_%s_timeout,\n", learner_spec->name);
+			fprintf(f, "\t\t\t.n_timeouts = "
+				"sizeof(learner_%s_timeout) / sizeof(learner_%s_timeout[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t.timeout = NULL,\n");
+			fprintf(f, "\t\t\t.n_timeouts = 0,\n");
+		}
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *apply%u_initial_instructions[] = {\n", i);
+
+		for (j = 0; j < apply_spec->n_instructions; j++) {
+			const char *instr = apply_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct apply_spec apply[] = {\n");
+
+	for (i = 0; i < s->n_apply; i++) {
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t.instructions = apply%u_initial_instructions,\n", i);
+		fprintf(f, "\t.n_instructions = "
+			"sizeof(apply%u_initial_instructions) / "
+			"sizeof(apply%u_initial_instructions[0]),\n",
+			i,
+			i);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* pipeline. */
+	fprintf(f, "struct pipeline_spec pipeline_spec = {\n");
+	fprintf(f, "\t.extobjs = extobjs,\n");
+	fprintf(f, "\t.structs = structs,\n");
+	fprintf(f, "\t.headers = headers,\n");
+	fprintf(f, "\t.metadata = metadata,\n");
+	fprintf(f, "\t.actions = actions,\n");
+	fprintf(f, "\t.tables = tables,\n");
+	fprintf(f, "\t.selectors = selectors,\n");
+	fprintf(f, "\t.learners = learners,\n");
+	fprintf(f, "\t.regarrays = regarrays,\n");
+	fprintf(f, "\t.metarrays = metarrays,\n");
+	fprintf(f, "\t.apply = apply,\n");
+	fprintf(f, "\t.n_extobjs = sizeof(extobjs) / sizeof(extobjs[0]),\n");
+	fprintf(f, "\t.n_structs = sizeof(structs) / sizeof(structs[0]),\n");
+	fprintf(f, "\t.n_headers = sizeof(headers) / sizeof(headers[0]),\n");
+	fprintf(f, "\t.n_metadata = sizeof(metadata) / sizeof(metadata[0]),\n");
+	fprintf(f, "\t.n_actions = sizeof(actions) / sizeof(actions[0]),\n");
+	fprintf(f, "\t.n_tables = sizeof(tables) / sizeof(tables[0]),\n");
+	fprintf(f, "\t.n_selectors = sizeof(selectors) / sizeof(selectors[0]),\n");
+	fprintf(f, "\t.n_learners = sizeof(learners) / sizeof(learners[0]),\n");
+	fprintf(f, "\t.n_regarrays = sizeof(regarrays) / sizeof(regarrays[0]),\n");
+	fprintf(f, "\t.n_metarrays = sizeof(metarrays) / sizeof(metarrays[0]),\n");
+	fprintf(f, "\t.n_apply = sizeof(apply) / sizeof(apply[0]),\n");
+	fprintf(f, "};\n");
+}
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 4f3a0b5958..707b99ba09 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,6 +206,11 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s);
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V2 5/9] pipeline: add API for pipeline code generation
  2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                     ` (2 preceding siblings ...)
  2022-07-18 13:25   ` [PATCH V2 4/9] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
@ 2022-07-18 13:25   ` Cristian Dumitrescu
  2022-07-18 13:26   ` [PATCH V2 6/9] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:25 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the C code generation for the pipeline was hidden under
the hood; now, we make this an explicit API operation. Besides the
functions for the pipeline actions and the pipeline instructions,
the generated C source code now includes the pipeline specification
structure required for the pipeline configuration operations.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline.c | 94 +++++++++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline.h | 25 +++++++++
 lib/pipeline/version.map        |  3 ++
 3 files changed, 122 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index 3e1c6e9edb..52760111fd 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -18,6 +18,7 @@
 #include <rte_swx_table_wm.h>
 
 #include "rte_swx_pipeline_internal.h"
+#include "rte_swx_pipeline_spec.h"
 
 #define CHECK(condition, err_code)                                             \
 do {                                                                           \
@@ -13476,3 +13477,96 @@ pipeline_compile(struct rte_swx_pipeline *p)
 
 	return status;
 }
+
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg)
+
+{
+	struct rte_swx_pipeline *p = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!spec_file || !code_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	status = rte_swx_pipeline_config(&p, 0);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline configuration error.";
+		goto free;
+	}
+
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto free;
+	}
+
+	/*
+	 * Pipeline code generation.
+	 */
+
+	/* Instruction Group List (IGL) computation: the pipeline configuration must be done first,
+	 * but there is no need for the pipeline build to be done as well.
+	 */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
+		goto free;
+	}
+
+	/* Header file inclusion. */
+	fprintf(code_file, "#include \"rte_swx_pipeline_internal.h\"\n");
+	fprintf(code_file, "#include \"rte_swx_pipeline_spec.h\"\n\n");
+
+	/* Code generation for the pipeline specification. */
+	pipeline_spec_codegen(code_file, s);
+	fprintf(code_file, "\n");
+
+	/* Code generation for the action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		fprintf(code_file, "/**\n * Action %s\n */\n\n", a->name);
+
+		action_data_codegen(a, code_file);
+		fprintf(code_file, "\n");
+
+		action_instr_codegen(a, code_file);
+		fprintf(code_file, "\n");
+	}
+
+	/* Code generation for the pipeline instructions. */
+	instruction_group_list_codegen(igl, p, code_file);
+
+free:
+	instruction_group_list_free(igl);
+	rte_swx_pipeline_free(p);
+	pipeline_spec_free(s);
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index c41ca5cb15..2bd019b05f 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -941,6 +941,31 @@ __rte_experimental
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p);
 
+/**
+ * Pipeline C code generate based on input specification file
+ *
+ * @param[in] spec_file
+ *   Pipeline specification file (.spec) provided as input.
+ * @param[in] code_file
+ *   Pipeline C language file (.c) to be generated.
+ * @param[out] err_line
+ *   In case of error and non-NULL, the line number within the *spec* file where
+ *   the error occurred. The first line number in the file is 1.
+ * @param[out] err_msg
+ *   In case of error and non-NULL, the error message.
+ * @return
+ *   0 on success or the following error codes otherwise:
+ *   -EINVAL: Invalid argument;
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -EEXIST: Resource with the same name already exists.
+ */
+__rte_experimental
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg);
+
 /**
  * Pipeline build from specification file
  *
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 8312307a7a..51165d48cf 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -145,4 +145,7 @@ EXPERIMENTAL {
 	rte_swx_ctl_pipeline_learner_timeout_get;
 	rte_swx_ctl_pipeline_learner_timeout_set;
 	rte_swx_pipeline_hash_func_register;
+
+	#added in 22.11
+	rte_swx_pipeline_codegen;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V2 6/9] pipeline: add API for shared library-based pipeline build
  2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                     ` (3 preceding siblings ...)
  2022-07-18 13:25   ` [PATCH V2 5/9] pipeline: add API for pipeline code generation Cristian Dumitrescu
@ 2022-07-18 13:26   ` Cristian Dumitrescu
  2022-07-18 13:26   ` [PATCH V2 7/9] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:26 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the pipeline build operation was done based on the
specification file (typically produced by the P4 compiler), then the C
code with optimized functions for the pipeline actions and
instructions was generated, built into a shared object library, loaded
and installed into the pipeline in a completely hardcoded and
non-customizable way.

Now, this process is split into three explicit stages:
i) code generation (specification file -> C file);
ii) code build (C file -> shared object library);
iii) code installation (library load into the pipeline).

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c              |  20 +-
 lib/pipeline/rte_swx_pipeline.c      | 289 +++++++++------------------
 lib/pipeline/rte_swx_pipeline.h      |  22 +-
 lib/pipeline/rte_swx_pipeline_spec.c |  51 -----
 lib/pipeline/version.map             |   2 +-
 5 files changed, 108 insertions(+), 276 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index ad553f19ab..1f75b5dc9d 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -984,7 +984,7 @@ cmd_pipeline_port_out(char **tokens,
 }
 
 static const char cmd_pipeline_build_help[] =
-"pipeline <pipeline_name> build <spec_file>\n";
+"pipeline <pipeline_name> build <lib_file>\n";
 
 static void
 cmd_pipeline_build(char **tokens,
@@ -994,9 +994,6 @@ cmd_pipeline_build(char **tokens,
 	void *obj)
 {
 	struct pipeline *p = NULL;
-	FILE *spec = NULL;
-	uint32_t err_line;
-	const char *err_msg;
 	int status;
 
 	if (n_tokens != 4) {
@@ -1010,20 +1007,9 @@ cmd_pipeline_build(char **tokens,
 		return;
 	}
 
-	spec = fopen(tokens[3], "r");
-	if (!spec) {
-		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
-		return;
-	}
-
-	status = rte_swx_pipeline_build_from_spec(p->p,
-		spec,
-		&err_line,
-		&err_msg);
-	fclose(spec);
+	status = rte_swx_pipeline_build_from_lib(p->p, tokens[3]);
 	if (status) {
-		snprintf(out, out_size, "Error %d at line %u: %s\n.",
-			status, err_line, err_msg);
+		snprintf(out, out_size, "Pipeline build error (%d).", status);
 		return;
 	}
 
diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index 52760111fd..03414bfd1f 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -9807,9 +9807,6 @@ rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p,
 	return 0;
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p);
-
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 {
@@ -9899,8 +9896,6 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 
 	p->build_done = 1;
 
-	pipeline_compile(p);
-
 	return 0;
 
 error:
@@ -13222,160 +13217,6 @@ instruction_group_list_custom_instructions_count(struct instruction_group_list *
 	return n_custom_instr;
 }
 
-static int
-pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	FILE *f = NULL;
-
-	/* Create the .c file. */
-	f = fopen("/tmp/pipeline.c", "w");
-	if (!f)
-		return -EIO;
-
-	/* Include the .h file. */
-	fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n");
-
-	/* Add the code for each action. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		fprintf(f, "/**\n * Action %s\n */\n\n", a->name);
-
-		action_data_codegen(a, f);
-
-		fprintf(f, "\n");
-
-		action_instr_codegen(a, f);
-
-		fprintf(f, "\n");
-	}
-
-	/* Add the pipeline code. */
-	instruction_group_list_codegen(igl, p, f);
-
-	/* Close the .c file. */
-	fclose(f);
-
-	return 0;
-}
-
-#ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE
-#define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096
-#endif
-
-static int
-pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	struct instruction_group *g;
-	char *dir_in, *buffer = NULL;
-	const char *dir_out;
-	int status = 0;
-
-	/* Get the environment variables. */
-	dir_in = getenv("RTE_INSTALL_DIR");
-	if (!dir_in) {
-		status = -EINVAL;
-		goto free;
-	}
-
-	dir_out = "/tmp";
-
-	/* Memory allocation for the command buffer. */
-	buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE);
-	if (!buffer) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c "
-		 "-I %s/lib/pipeline "
-		 "-I %s/lib/eal/include "
-		 "-I %s/lib/eal/x86/include "
-		 "-I %s/lib/eal/include/generic "
-		 "-I %s/lib/meter "
-		 "-I %s/lib/port "
-		 "-I %s/lib/table "
-		 "-I %s/lib/pipeline "
-		 "-I %s/config "
-		 "-I %s/build "
-		 "-I %s/lib/eal/linux/include "
-		 ">%s/pipeline.log 2>&1 "
-		 "&& "
-		 "gcc -shared %s/pipeline.o -o %s/libpipeline.so "
-		 ">>%s/pipeline.log 2>&1",
-		 dir_out,
-		 dir_out,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_out,
-		 dir_out,
-		 dir_out,
-		 dir_out);
-
-	/* Build the shared object library. */
-	status = system(buffer);
-	if (status)
-		goto free;
-
-	/* Open library. */
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "%s/libpipeline.so",
-		 dir_out);
-
-	p->lib = dlopen(buffer, RTLD_LAZY);
-	if (!p->lib) {
-		status = -EIO;
-		goto free;
-	}
-
-	/* Get the action function symbols. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name);
-
-		p->action_funcs[a->id] = dlsym(p->lib, buffer);
-		if (!p->action_funcs[a->id]) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-	/* Get the pipeline function symbols. */
-	TAILQ_FOREACH(g, igl, node) {
-		if (g->first_instr_id == g->last_instr_id)
-			continue;
-
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id);
-
-		g->func = dlsym(p->lib, buffer);
-		if (!g->func) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-free:
-	if (status && p->lib) {
-		dlclose(p->lib);
-		p->lib = NULL;
-	}
-
-	free(buffer);
-
-	return status;
-}
-
 static int
 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused,
 		      struct instruction_group_list *igl)
@@ -13443,41 +13284,6 @@ pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
 	instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions);
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p)
-{
-	struct instruction_group_list *igl = NULL;
-	int status = 0;
-
-	igl = instruction_group_list_create(p);
-	if (!igl) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	/* Code generation. */
-	status = pipeline_codegen(p, igl);
-	if (status)
-		goto free;
-
-	/* Build and load the shared object library. */
-	status = pipeline_libload(p, igl);
-	if (status)
-		goto free;
-
-	/* Adjust instructions. */
-	status = pipeline_adjust_check(p, igl);
-	if (status)
-		goto free;
-
-	pipeline_adjust(p, igl);
-
-free:
-	instruction_group_list_free(igl);
-
-	return status;
-}
-
 int
 rte_swx_pipeline_codegen(FILE *spec_file,
 			 FILE *code_file,
@@ -13570,3 +13376,98 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 
 	return status;
 }
+
+int
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline *p,
+				const char *lib_file_name)
+{
+	void *lib = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	struct instruction_group *g;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!p || p->build_done || !lib_file_name || !lib_file_name[0]) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Open the library. */
+	lib = dlopen(lib_file_name, RTLD_LAZY);
+	if (!lib) {
+		status = -EIO;
+		goto free;
+	}
+
+	/* Get the pipeline specification structure from the library. */
+	s = dlsym(lib, "pipeline_spec");
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration based on the specification structure. */
+	status = pipeline_spec_configure(p, s, NULL);
+	if (status)
+		goto free;
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status)
+		goto free;
+
+	/* Action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		snprintf(name, sizeof(name), "action_%s_run", a->name);
+
+		p->action_funcs[a->id] = dlsym(lib, name);
+		if (!p->action_funcs[a->id]) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	/* Pipeline instructions. */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		status = -ENOMEM;
+		goto free;
+	}
+
+	TAILQ_FOREACH(g, igl, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		if (g->first_instr_id == g->last_instr_id)
+			continue;
+
+		snprintf(name, sizeof(name), "pipeline_func_%u", g->group_id);
+
+		g->func = dlsym(lib, name);
+		if (!g->func) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	status = pipeline_adjust_check(p, igl);
+	if (status)
+		goto free;
+
+	pipeline_adjust(p, igl);
+
+	p->lib = lib;
+
+free:
+	if (status && lib) {
+		dlclose(lib);
+		p->lib = NULL;
+	}
+
+	instruction_group_list_free(igl);
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index 2bd019b05f..cb834cd64d 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -967,30 +967,26 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 			 const char **err_msg);
 
 /**
- * Pipeline build from specification file
+ * Pipeline build from shared object library
+ *
+ * The shared object library must be built from the C language source code file
+ * previously generated by the rte_swx_pipeline_codegen() API function.
  *
  * @param[in] p
  *   Pipeline handle.
- * @param[in] spec
- *   Pipeline specification file.
- * @param[out] err_line
- *   In case of error and non-NULL, the line number within the *spec* file where
- *   the error occurred. The first line number in the file is 1.
- * @param[out] err_msg
- *   In case of error and non-NULL, the error message.
+ * @param[in] lib_file_name
+ *   Shared object library file name.
  * @return
  *   0 on success or the following error codes otherwise:
  *   -EINVAL: Invalid argument;
  *   -ENOMEM: Not enough space/cannot allocate memory;
- *   -EEXIST: Resource with the same name already exists;
+ *   -EEXIST: Pipeline was already built successfully;
  *   -ENODEV: Extern object or table creation error.
  */
 __rte_experimental
 int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg);
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline *p,
+				const char *lib_file_name);
 
 /**
  * Pipeline run
diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index bf21fe17ba..d6650fcc80 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -3515,54 +3515,3 @@ pipeline_spec_configure(struct rte_swx_pipeline *p,
 
 	return 0;
 }
-
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec_file,
-				 uint32_t *err_line,
-				 const char **err_msg)
-{
-	struct pipeline_spec *s = NULL;
-	int status = 0;
-
-	/* Check the input arguments. */
-	if (!p || !spec_file) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Invalid input argument.";
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Spec file parse. */
-	s = pipeline_spec_parse(spec_file, err_line, err_msg);
-	if (!s) {
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Pipeline configure. */
-	status = pipeline_spec_configure(p, s, err_msg);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		goto error;
-	}
-
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
-
-error:
-	pipeline_spec_free(s);
-	return status;
-}
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 51165d48cf..810cc56467 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -82,7 +82,6 @@ EXPERIMENTAL {
 	rte_swx_ctl_table_ops_get;
 	rte_swx_pipeline_action_config;
 	rte_swx_pipeline_build;
-	rte_swx_pipeline_build_from_spec;
 	rte_swx_pipeline_config;
 	rte_swx_pipeline_extern_func_register;
 	rte_swx_pipeline_extern_object_config;
@@ -148,4 +147,5 @@ EXPERIMENTAL {
 
 	#added in 22.11
 	rte_swx_pipeline_codegen;
+	rte_swx_pipeline_build_from_lib;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V2 7/9] examples/pipeline: add CLI command for pipeline code generation
  2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                     ` (4 preceding siblings ...)
  2022-07-18 13:26   ` [PATCH V2 6/9] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
@ 2022-07-18 13:26   ` Cristian Dumitrescu
  2022-07-18 13:26   ` [PATCH V2 8/9] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:26 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the pipeline code generation operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 61 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 1f75b5dc9d..fdaf5dd16b 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -983,6 +983,53 @@ cmd_pipeline_port_out(char **tokens,
 	}
 }
 
+static const char cmd_pipeline_codegen_help[] =
+"pipeline codegen <spec_file> <code_file>\n";
+
+static void
+cmd_pipeline_codegen(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	FILE *spec_file = NULL;
+	FILE *code_file = NULL;
+	uint32_t err_line;
+	const char *err_msg;
+	int status;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	spec_file = fopen(tokens[2], "r");
+	if (!spec_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[2]);
+		return;
+	}
+
+	code_file = fopen(tokens[3], "w");
+	if (!code_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
+		return;
+	}
+
+	status = rte_swx_pipeline_codegen(spec_file,
+					  code_file,
+					  &err_line,
+					  &err_msg);
+
+	fclose(spec_file);
+	fclose(code_file);
+
+	if (status) {
+		snprintf(out, out_size, "Error %d at line %u: %s\n.",
+			status, err_line, err_msg);
+		return;
+	}
+}
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build <lib_file>\n";
 
@@ -2962,6 +3009,7 @@ cmd_help(char **tokens,
 			"\tpipeline create\n"
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
+			"\tpipeline codegen\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3031,6 +3079,12 @@ cmd_help(char **tokens,
 		}
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3309,6 +3363,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "codegen") == 0)) {
+			cmd_pipeline_codegen(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V2 8/9] examples/pipeline: add CLI command for shared library build
  2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                     ` (5 preceding siblings ...)
  2022-07-18 13:26   ` [PATCH V2 7/9] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
@ 2022-07-18 13:26   ` Cristian Dumitrescu
  2022-07-18 13:26   ` [PATCH V2 9/9] examples/pipeline: call CLI commands for code generation and build Cristian Dumitrescu
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
  8 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:26 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the shared object library build operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 147 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 143 insertions(+), 4 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index fdaf5dd16b..f1d2fbf52d 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -6,6 +6,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_ethdev.h>
@@ -25,6 +26,10 @@
 #define CMD_MAX_TOKENS     256
 #endif
 
+#ifndef MAX_LINE_SIZE
+#define MAX_LINE_SIZE 2048
+#endif
+
 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
@@ -1030,6 +1035,130 @@ cmd_pipeline_codegen(char **tokens,
 		return;
 	}
 }
+
+static const char cmd_pipeline_libbuild_help[] =
+"pipeline libbuild <code_file> <lib_file>\n";
+
+static void
+cmd_pipeline_libbuild(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	char *code_file, *lib_file, *obj_file = NULL, *log_file = NULL;
+	char *install_dir, *buffer = NULL;
+	size_t length;
+	int status = 0;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		goto free;
+	}
+
+	install_dir = getenv("RTE_INSTALL_DIR");
+	if (!install_dir) {
+		snprintf(out, out_size, "Error: Environment variable RTE_INSTALL_DIR is not set.");
+		return;
+	}
+
+	snprintf(out, out_size, "Using DPDK source code from \"%s\".\n", install_dir);
+	out_size -= strlen(out);
+	out += strlen(out);
+
+	code_file = tokens[2];
+	length = strnlen(code_file, MAX_LINE_SIZE);
+	if ((length < 3) ||
+	    (code_file[length - 2] != '.') ||
+	    (code_file[length - 1] != 'c')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "code_file");
+		goto free;
+	}
+
+	lib_file = tokens[3];
+	length = strnlen(lib_file, MAX_LINE_SIZE);
+	if ((length < 4) ||
+	    (lib_file[length - 3] != '.') ||
+	    (lib_file[length - 2] != 's') ||
+	    (lib_file[length - 1] != 'o')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "lib_file");
+		goto free;
+	}
+
+	obj_file = malloc(length);
+	log_file = malloc(length + 2);
+	if (!obj_file || !log_file) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		goto free;
+	}
+
+	memcpy(obj_file, lib_file, length - 2);
+	obj_file[length - 2] = 'o';
+	obj_file[length - 1] = 0;
+
+	memcpy(log_file, lib_file, length - 2);
+	log_file[length - 2] = 'l';
+	log_file[length - 1] = 'o';
+	log_file[length] = 'g';
+	log_file[length + 1] = 0;
+
+	buffer = malloc(MAX_LINE_SIZE);
+	if (!buffer) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		return;
+	}
+
+	snprintf(buffer,
+		 MAX_LINE_SIZE,
+		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s %s "
+		 "-I %s/lib/pipeline "
+		 "-I %s/lib/eal/include "
+		 "-I %s/lib/eal/x86/include "
+		 "-I %s/lib/eal/include/generic "
+		 "-I %s/lib/meter "
+		 "-I %s/lib/port "
+		 "-I %s/lib/table "
+		 "-I %s/lib/pipeline "
+		 "-I %s/config "
+		 "-I %s/build "
+		 "-I %s/lib/eal/linux/include "
+		 ">%s 2>&1 "
+		 "&& "
+		 "gcc -shared %s -o %s "
+		 ">>%s 2>&1",
+		 obj_file,
+		 code_file,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 log_file,
+		 obj_file,
+		 lib_file,
+		 log_file);
+
+	status = system(buffer);
+	if (status) {
+		snprintf(out,
+			 out_size,
+			 "Library build failed, see file \"%s\" for details.\n",
+			 log_file);
+		goto free;
+	}
+
+free:
+	free(obj_file);
+	free(log_file);
+	free(buffer);
+}
+
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build <lib_file>\n";
 
@@ -1080,10 +1209,6 @@ table_entry_free(struct rte_swx_table_entry *entry)
 	free(entry);
 }
 
-#ifndef MAX_LINE_SIZE
-#define MAX_LINE_SIZE 2048
-#endif
-
 static int
 pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p,
 			   const char *table_name,
@@ -3010,6 +3135,7 @@ cmd_help(char **tokens,
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
+			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3085,6 +3211,12 @@ cmd_help(char **tokens,
 		return;
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "libbuild") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_libbuild_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3370,6 +3502,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "libbuild") == 0)) {
+			cmd_pipeline_libbuild(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V2 9/9] examples/pipeline: call CLI commands for code generation and build
  2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                     ` (6 preceding siblings ...)
  2022-07-18 13:26   ` [PATCH V2 8/9] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
@ 2022-07-18 13:26   ` Cristian Dumitrescu
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
  8 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-18 13:26 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Update the example CLI scripts with the commands for code generation
and shared object library build.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/examples/fib.cli               | 8 +++++++-
 examples/pipeline/examples/hash_func.cli         | 8 +++++++-
 examples/pipeline/examples/l2fwd.cli             | 8 +++++++-
 examples/pipeline/examples/l2fwd_macswp.cli      | 8 +++++++-
 examples/pipeline/examples/l2fwd_macswp_pcap.cli | 8 +++++++-
 examples/pipeline/examples/l2fwd_pcap.cli        | 8 +++++++-
 examples/pipeline/examples/learner.cli           | 8 +++++++-
 examples/pipeline/examples/meter.cli             | 8 +++++++-
 examples/pipeline/examples/mirroring.cli         | 8 +++++++-
 examples/pipeline/examples/recirculation.cli     | 8 +++++++-
 examples/pipeline/examples/registers.cli         | 8 +++++++-
 examples/pipeline/examples/selector.cli          | 8 +++++++-
 examples/pipeline/examples/varbit.cli            | 8 +++++++-
 examples/pipeline/examples/vxlan.cli             | 8 +++++++-
 examples/pipeline/examples/vxlan_pcap.cli        | 8 +++++++-
 15 files changed, 105 insertions(+), 15 deletions(-)

diff --git a/examples/pipeline/examples/fib.cli b/examples/pipeline/examples/fib.cli
index 93ab2b08f8..8b55175bf3 100644
--- a/examples/pipeline/examples/fib.cli
+++ b/examples/pipeline/examples/fib.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/fib.spec /tmp/fib.c
+pipeline libbuild /tmp/fib.c /tmp/fib.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -26,7 +32,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/fib.spec
+pipeline PIPELINE0 build /tmp/fib.so
 
 ;
 ; Initial set of table entries.
diff --git a/examples/pipeline/examples/hash_func.cli b/examples/pipeline/examples/hash_func.cli
index d65cd62d17..f7bb28b28b 100644
--- a/examples/pipeline/examples/hash_func.cli
+++ b/examples/pipeline/examples/hash_func.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/hash_func.spec /tmp/hash_func.c
+pipeline libbuild /tmp/hash_func.c /tmp/hash_func.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -26,7 +32,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/hash_func.spec
+pipeline PIPELINE0 build /tmp/hash_func.so
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/l2fwd.cli b/examples/pipeline/examples/l2fwd.cli
index d89caf2d0a..a71727309b 100644
--- a/examples/pipeline/examples/l2fwd.cli
+++ b/examples/pipeline/examples/l2fwd.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -20,6 +26,6 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+pipeline PIPELINE0 build /tmp/l2fwd.so
 
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp.cli b/examples/pipeline/examples/l2fwd_macswp.cli
index 0f2a89ac5b..d8f5f9f735 100644
--- a/examples/pipeline/examples/l2fwd_macswp.cli
+++ b/examples/pipeline/examples/l2fwd_macswp.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -20,6 +26,6 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+pipeline PIPELINE0 build /tmp/l2fwd_macswp.so
 
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp_pcap.cli b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
index e9656fe3c2..bd077876ff 100644
--- a/examples/pipeline/examples/l2fwd_macswp_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 pipeline PIPELINE0 create 0
@@ -15,6 +21,6 @@ pipeline PIPELINE0 port out 1 sink none
 pipeline PIPELINE0 port out 2 sink none
 pipeline PIPELINE0 port out 3 sink none
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+pipeline PIPELINE0 build /tmp/l2fwd_macswp.so
 
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_pcap.cli b/examples/pipeline/examples/l2fwd_pcap.cli
index 23fcb199f1..2e56a116af 100644
--- a/examples/pipeline/examples/l2fwd_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_pcap.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 pipeline PIPELINE0 create 0
@@ -15,6 +21,6 @@ pipeline PIPELINE0 port out 1 sink none
 pipeline PIPELINE0 port out 2 sink none
 pipeline PIPELINE0 port out 3 sink none
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+pipeline PIPELINE0 build /tmp/l2fwd.so
 
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/learner.cli b/examples/pipeline/examples/learner.cli
index 688ce34f34..10eb2af417 100644
--- a/examples/pipeline/examples/learner.cli
+++ b/examples/pipeline/examples/learner.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/learner.spec /tmp/learner.c
+pipeline libbuild /tmp/learner.c /tmp/learner.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -26,7 +32,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/learner.spec
+pipeline PIPELINE0 build /tmp/learner.so
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/meter.cli b/examples/pipeline/examples/meter.cli
index b29ed24022..9c22014f46 100644
--- a/examples/pipeline/examples/meter.cli
+++ b/examples/pipeline/examples/meter.cli
@@ -4,6 +4,12 @@
 ; Example command line:
 ;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/meter.cli
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/meter.spec /tmp/meter.c
+pipeline libbuild /tmp/meter.c /tmp/meter.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -23,7 +29,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/meter.spec
+pipeline PIPELINE0 build /tmp/meter.so
 
 pipeline PIPELINE0 meter profile platinum add cir 46000000 pir 138000000 cbs 1000000 pbs 1000000
 pipeline PIPELINE0 meter meters from 0 to 15 set profile platinum
diff --git a/examples/pipeline/examples/mirroring.cli b/examples/pipeline/examples/mirroring.cli
index 46d57db4ec..9614f64d38 100644
--- a/examples/pipeline/examples/mirroring.cli
+++ b/examples/pipeline/examples/mirroring.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/mirroring.spec /tmp/mirroring.c
+pipeline libbuild /tmp/mirroring.c /tmp/mirroring.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -27,7 +33,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/mirroring.spec
+pipeline PIPELINE0 build /tmp/mirroring.so
 
 ;
 ; Packet mirroring sessions.
diff --git a/examples/pipeline/examples/recirculation.cli b/examples/pipeline/examples/recirculation.cli
index f855c5c327..bd114e91cd 100644
--- a/examples/pipeline/examples/recirculation.cli
+++ b/examples/pipeline/examples/recirculation.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/recirculation.spec /tmp/recirculation.c
+pipeline libbuild /tmp/recirculation.c /tmp/recirculation.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -26,7 +32,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/recirculation.spec
+pipeline PIPELINE0 build /tmp/recirculation.so
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/registers.cli b/examples/pipeline/examples/registers.cli
index 8d026294cb..3d9eeb0d5c 100644
--- a/examples/pipeline/examples/registers.cli
+++ b/examples/pipeline/examples/registers.cli
@@ -4,6 +4,12 @@
 ; Example command line:
 ;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/registers.cli
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/registers.spec /tmp/registers.c
+pipeline libbuild /tmp/registers.c /tmp/registers.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -23,6 +29,6 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/registers.spec
+pipeline PIPELINE0 build /tmp/registers.so
 
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/selector.cli b/examples/pipeline/examples/selector.cli
index 123782c57b..6c7d032b10 100644
--- a/examples/pipeline/examples/selector.cli
+++ b/examples/pipeline/examples/selector.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/selector.spec /tmp/selector.c
+pipeline libbuild /tmp/selector.c /tmp/selector.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -20,7 +26,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/selector.spec
+pipeline PIPELINE0 build /tmp/selector.so
 
 pipeline PIPELINE0 selector s group add
 pipeline PIPELINE0 selector s group member add ./examples/pipeline/examples/selector.txt
diff --git a/examples/pipeline/examples/varbit.cli b/examples/pipeline/examples/varbit.cli
index 9caeb9ca26..545cde262e 100644
--- a/examples/pipeline/examples/varbit.cli
+++ b/examples/pipeline/examples/varbit.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/varbit.spec /tmp/varbit.c
+pipeline libbuild /tmp/varbit.c /tmp/varbit.so
+
 ;
 ; Customize the LINK parameters to match your setup.
 ;
@@ -26,7 +32,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/varbit.spec
+pipeline PIPELINE0 build /tmp/varbit.so
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/vxlan.cli b/examples/pipeline/examples/vxlan.cli
index 444f3f7bd8..321a28ba44 100644
--- a/examples/pipeline/examples/vxlan.cli
+++ b/examples/pipeline/examples/vxlan.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
@@ -20,7 +26,7 @@ pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
 pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
 pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+pipeline PIPELINE0 build /tmp/vxlan.so
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
diff --git a/examples/pipeline/examples/vxlan_pcap.cli b/examples/pipeline/examples/vxlan_pcap.cli
index 83fca8d0d9..596169f933 100644
--- a/examples/pipeline/examples/vxlan_pcap.cli
+++ b/examples/pipeline/examples/vxlan_pcap.cli
@@ -1,6 +1,12 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+;
+; Pipeline code generation & shared object library build
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
+
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
 pipeline PIPELINE0 create 0
@@ -15,7 +21,7 @@ pipeline PIPELINE0 port out 1 sink none
 pipeline PIPELINE0 port out 2 sink none
 pipeline PIPELINE0 port out 3 sink none
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+pipeline PIPELINE0 build /tmp/vxlan.so
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 01/17] pipeline: add pipeline name
  2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                     ` (7 preceding siblings ...)
  2022-07-18 13:26   ` [PATCH V2 9/9] examples/pipeline: call CLI commands for code generation and build Cristian Dumitrescu
@ 2022-07-27 22:36   ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
                       ` (16 more replies)
  8 siblings, 17 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add an unique name to every pipeline. This enables the library to
maintain a list of the existing pipeline objects, which can be
queried by the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/obj.c                  |   2 +-
 lib/pipeline/rte_swx_ctl.c               |  99 +++++++++++++++++++++
 lib/pipeline/rte_swx_ctl.h               |  15 ++++
 lib/pipeline/rte_swx_pipeline.c          | 107 ++++++++++++++++++++++-
 lib/pipeline/rte_swx_pipeline.h          |  18 +++-
 lib/pipeline/rte_swx_pipeline_internal.h |   2 +
 lib/pipeline/version.map                 |   4 +
 7 files changed, 244 insertions(+), 3 deletions(-)

diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index b79f044ac7..967342c580 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -533,7 +533,7 @@ pipeline_create(struct obj *obj, const char *name, int numa_node)
 		return NULL;
 
 	/* Resource create */
-	status = rte_swx_pipeline_config(&p, numa_node);
+	status = rte_swx_pipeline_config(&p, name, numa_node);
 	if (status)
 		goto error;
 
diff --git a/lib/pipeline/rte_swx_ctl.c b/lib/pipeline/rte_swx_ctl.c
index 710e89a46a..1b776fc543 100644
--- a/lib/pipeline/rte_swx_ctl.c
+++ b/lib/pipeline/rte_swx_ctl.c
@@ -9,6 +9,8 @@
 
 #include <rte_common.h>
 #include <rte_byteorder.h>
+#include <rte_tailq.h>
+#include <rte_eal_memconfig.h>
 
 #include <rte_swx_table_selector.h>
 
@@ -1157,12 +1159,103 @@ table_state_create(struct rte_swx_ctl_pipeline *ctl)
 	return status;
 }
 
+/* Global list of pipeline instances. */
+TAILQ_HEAD(rte_swx_ctl_pipeline_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_swx_ctl_pipeline_tailq = {
+	.name = "RTE_SWX_CTL_PIPELINE",
+};
+
+EAL_REGISTER_TAILQ(rte_swx_ctl_pipeline_tailq)
+
+struct rte_swx_ctl_pipeline *
+rte_swx_ctl_pipeline_find(const char *name)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	if (!name || !name[0] || (strnlen(name, RTE_SWX_CTL_NAME_SIZE) >= RTE_SWX_CTL_NAME_SIZE))
+		return NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_read_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		struct rte_swx_ctl_pipeline *ctl = (struct rte_swx_ctl_pipeline *)te->data;
+
+		if (!strncmp(name, ctl->info.name, sizeof(ctl->info.name))) {
+			rte_mcfg_tailq_read_unlock();
+			return ctl;
+		}
+	}
+
+	rte_mcfg_tailq_read_unlock();
+	return NULL;
+}
+
+static int
+ctl_register(struct rte_swx_ctl_pipeline *ctl)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		struct rte_swx_ctl_pipeline *ctl_crt = (struct rte_swx_ctl_pipeline *)te->data;
+
+		if (!strncmp(ctl->info.name, ctl_crt->info.name, sizeof(ctl->info.name))) {
+			rte_mcfg_tailq_write_unlock();
+			return -EEXIST;
+		}
+	}
+
+	te = calloc(1, sizeof(struct rte_tailq_entry));
+	if (!te) {
+		rte_mcfg_tailq_write_unlock();
+		return -ENOMEM;
+	}
+
+	te->data = (void *)ctl;
+	TAILQ_INSERT_TAIL(ctl_list, te, next);
+	rte_mcfg_tailq_write_unlock();
+	return 0;
+}
+
+static void
+ctl_unregister(struct rte_swx_ctl_pipeline *ctl)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		if (te->data == (void *)ctl) {
+			TAILQ_REMOVE(ctl_list, te, next);
+			rte_mcfg_tailq_write_unlock();
+			free(te);
+			return;
+		}
+	}
+
+	rte_mcfg_tailq_write_unlock();
+}
+
 void
 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
 {
 	if (!ctl)
 		return;
 
+	if (ctl->info.name[0])
+		ctl_unregister(ctl);
+
 	action_free(ctl);
 
 	table_state_free(ctl);
@@ -1441,6 +1534,12 @@ rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
 	if (status)
 		goto error;
 
+	if (ctl->info.name[0]) {
+		status = ctl_register(ctl);
+		if (status)
+			goto error;
+	}
+
 	return ctl;
 
 error:
diff --git a/lib/pipeline/rte_swx_ctl.h b/lib/pipeline/rte_swx_ctl.h
index d771389d26..63ee479e47 100644
--- a/lib/pipeline/rte_swx_ctl.h
+++ b/lib/pipeline/rte_swx_ctl.h
@@ -35,6 +35,9 @@ struct rte_swx_pipeline;
 
 /** Pipeline info. */
 struct rte_swx_ctl_pipeline_info {
+	/** Pipeline name. */
+	char name[RTE_SWX_CTL_NAME_SIZE];
+
 	/** Number of input ports. */
 	uint32_t n_ports_in;
 
@@ -812,6 +815,18 @@ rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p,
 /** Pipeline control opaque data structure. */
 struct rte_swx_ctl_pipeline;
 
+/**
+ * Pipeline control find
+ *
+ * @param[in] name
+ *   Pipeline name.
+ * @return
+ *   Valid pipeline control handle if found or NULL otherwise.
+ */
+__rte_experimental
+struct rte_swx_ctl_pipeline *
+rte_swx_ctl_pipeline_find(const char *name);
+
 /**
  * Pipeline control create
  *
diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index 3e1c6e9edb..c8ccded4f8 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -6,6 +6,8 @@
 #include <errno.h>
 #include <dlfcn.h>
 
+#include <rte_tailq.h>
+#include <rte_eal_memconfig.h>
 #include <rte_jhash.h>
 #include <rte_hash_crc.h>
 
@@ -9578,6 +9580,95 @@ metarray_free(struct rte_swx_pipeline *p)
 /*
  * Pipeline.
  */
+
+/* Global list of pipeline instances. */
+TAILQ_HEAD(rte_swx_pipeline_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_swx_pipeline_tailq = {
+	.name = "RTE_SWX_PIPELINE",
+};
+
+EAL_REGISTER_TAILQ(rte_swx_pipeline_tailq)
+
+struct rte_swx_pipeline *
+rte_swx_pipeline_find(const char *name)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	if (!name || !name[0] || (strnlen(name, RTE_SWX_NAME_SIZE) >= RTE_SWX_NAME_SIZE))
+		return NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_read_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		struct rte_swx_pipeline *p = (struct rte_swx_pipeline *)te->data;
+
+		if (!strncmp(name, p->name, sizeof(p->name))) {
+			rte_mcfg_tailq_read_unlock();
+			return p;
+		}
+	}
+
+	rte_mcfg_tailq_read_unlock();
+	return NULL;
+}
+
+static int
+pipeline_register(struct rte_swx_pipeline *p)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		struct rte_swx_pipeline *pipeline = (struct rte_swx_pipeline *)te->data;
+
+		if (!strncmp(p->name, pipeline->name, sizeof(p->name))) {
+			rte_mcfg_tailq_write_unlock();
+			return -EEXIST;
+		}
+	}
+
+	te = calloc(1, sizeof(struct rte_tailq_entry));
+	if (!te) {
+		rte_mcfg_tailq_write_unlock();
+		return -ENOMEM;
+	}
+
+	te->data = (void *)p;
+	TAILQ_INSERT_TAIL(pipeline_list, te, next);
+	rte_mcfg_tailq_write_unlock();
+	return 0;
+}
+
+static void
+pipeline_unregister(struct rte_swx_pipeline *p)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		if (te->data == (void *)p) {
+			TAILQ_REMOVE(pipeline_list, te, next);
+			rte_mcfg_tailq_write_unlock();
+			free(te);
+			return;
+		}
+	}
+
+	rte_mcfg_tailq_write_unlock();
+}
+
 void
 rte_swx_pipeline_free(struct rte_swx_pipeline *p)
 {
@@ -9586,6 +9677,9 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p)
 	if (!p)
 		return;
 
+	if (p->name[0])
+		pipeline_unregister(p);
+
 	lib = p->lib;
 
 	free(p->instruction_data);
@@ -9720,13 +9814,14 @@ hash_funcs_register(struct rte_swx_pipeline *p)
 }
 
 int
-rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
+rte_swx_pipeline_config(struct rte_swx_pipeline **p, const char *name, int numa_node)
 {
 	struct rte_swx_pipeline *pipeline = NULL;
 	int status = 0;
 
 	/* Check input parameters. */
 	CHECK(p, EINVAL);
+	CHECK(!name || (strnlen(name, RTE_SWX_NAME_SIZE) < RTE_SWX_NAME_SIZE), EINVAL);
 
 	/* Memory allocation. */
 	pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
@@ -9736,6 +9831,9 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
 	}
 
 	/* Initialization. */
+	if (name)
+		strcpy(pipeline->name, name);
+
 	TAILQ_INIT(&pipeline->struct_types);
 	TAILQ_INIT(&pipeline->port_in_types);
 	TAILQ_INIT(&pipeline->ports_in);
@@ -9776,6 +9874,12 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
 	if (status)
 		goto error;
 
+	if (pipeline->name[0]) {
+		status = pipeline_register(pipeline);
+		if (status)
+			goto error;
+	}
+
 	*p = pipeline;
 	return 0;
 
@@ -9966,6 +10070,7 @@ rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p,
 	TAILQ_FOREACH(table, &p->tables, node)
 		n_tables++;
 
+	strcpy(pipeline->name, p->name);
 	pipeline->n_ports_in = p->n_ports_in;
 	pipeline->n_ports_out = p->n_ports_out;
 	pipeline->n_mirroring_slots = p->n_mirroring_slots;
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index c41ca5cb15..ef50a0fa70 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -44,22 +44,38 @@ extern "C" {
 /** Pipeline opaque data structure. */
 struct rte_swx_pipeline;
 
+/**
+ * Pipeline find
+ *
+ * @param[in] name
+ *   Pipeline name.
+ * @return
+ *   Valid pipeline handle if found or NULL otherwise.
+ */
+__rte_experimental
+struct rte_swx_pipeline *
+rte_swx_pipeline_find(const char *name);
+
 /**
  * Pipeline configure
  *
  * @param[out] p
  *   Pipeline handle. Must point to valid memory. Contains valid pipeline handle
  *   when the function returns successfully.
+ * @param[in] name
+ *   Pipeline unique name.
  * @param[in] numa_node
  *   Non-Uniform Memory Access (NUMA) node.
  * @return
  *   0 on success or the following error codes otherwise:
  *   -EINVAL: Invalid argument;
- *   -ENOMEM: Not enough space/cannot allocate memory.
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -EEXIST: Pipeline with this name already exists.
  */
 __rte_experimental
 int
 rte_swx_pipeline_config(struct rte_swx_pipeline **p,
+			const char *name,
 			int numa_node);
 
 /*
diff --git a/lib/pipeline/rte_swx_pipeline_internal.h b/lib/pipeline/rte_swx_pipeline_internal.h
index a35635efb7..588cad62b5 100644
--- a/lib/pipeline/rte_swx_pipeline_internal.h
+++ b/lib/pipeline/rte_swx_pipeline_internal.h
@@ -1459,6 +1459,8 @@ instr_operand_nbo(struct thread *t, const struct instr_operand *x)
 #endif
 
 struct rte_swx_pipeline {
+	char name[RTE_SWX_NAME_SIZE];
+
 	struct struct_type_tailq struct_types;
 	struct port_in_type_tailq port_in_types;
 	struct port_in_tailq ports_in;
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 8312307a7a..50029aadcf 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -145,4 +145,8 @@ EXPERIMENTAL {
 	rte_swx_ctl_pipeline_learner_timeout_get;
 	rte_swx_ctl_pipeline_learner_timeout_set;
 	rte_swx_pipeline_hash_func_register;
+
+	#added in 22.11
+	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 02/17] pipeline: move specification data structures to internal header
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
                       ` (15 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Move all the pipeline object specification data structures to an
internal header file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 126 +------------------
 lib/pipeline/rte_swx_pipeline_spec.h | 176 +++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 125 deletions(-)
 create mode 100644 lib/pipeline/rte_swx_pipeline_spec.h

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 904b9eb471..5e07b4f794 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -9,7 +9,7 @@
 
 #include <rte_common.h>
 
-#include "rte_swx_pipeline.h"
+#include "rte_swx_pipeline_spec.h"
 
 #ifndef MAX_LINE_LENGTH
 #define MAX_LINE_LENGTH 2048
@@ -34,15 +34,7 @@
 
 /*
  * extobj.
- *
- * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
  */
-struct extobj_spec {
-	char *name;
-	char *extern_type_name;
-	char *pragma;
-};
-
 static void
 extobj_spec_free(struct extobj_spec *s)
 {
@@ -104,18 +96,7 @@ extobj_statement_parse(struct extobj_spec *s,
 /*
  * struct.
  *
- * struct STRUCT_TYPE_NAME {
- *	bit<SIZE> | varbit<SIZE> FIELD_NAME
- *	...
- * }
  */
-struct struct_spec {
-	char *name;
-	struct rte_swx_field_params *fields;
-	uint32_t n_fields;
-	int varbit;
-};
-
 static void
 struct_spec_free(struct struct_spec *s)
 {
@@ -293,13 +274,7 @@ struct_block_parse(struct struct_spec *s,
 /*
  * header.
  *
- * header HEADER_NAME instanceof STRUCT_TYPE_NAME
  */
-struct header_spec {
-	char *name;
-	char *struct_type_name;
-};
-
 static void
 header_spec_free(struct header_spec *s)
 {
@@ -351,12 +326,7 @@ header_statement_parse(struct header_spec *s,
 /*
  * metadata.
  *
- * metadata instanceof STRUCT_TYPE_NAME
  */
-struct metadata_spec {
-	char *struct_type_name;
-};
-
 static void
 metadata_spec_free(struct metadata_spec *s)
 {
@@ -400,18 +370,7 @@ metadata_statement_parse(struct metadata_spec *s,
 /*
  * action.
  *
- * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
- *	INSTRUCTION
- *	...
- * }
  */
-struct action_spec {
-	char *name;
-	char *args_struct_type_name;
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 action_spec_free(struct action_spec *s)
 {
@@ -540,29 +499,7 @@ action_block_parse(struct action_spec *s,
 /*
  * table.
  *
- * table TABLE_NAME {
- *	key {
- *		MATCH_FIELD_NAME exact | wildcard | lpm
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly ]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	instanceof TABLE_TYPE_NAME
- *	pragma ARGS
- *	size SIZE
- * }
  */
-struct table_spec {
-	char *name;
-	struct rte_swx_pipeline_table_params params;
-	char *recommended_table_type_name;
-	char *args;
-	uint32_t size;
-};
-
 static void
 table_spec_free(struct table_spec *s)
 {
@@ -1084,22 +1021,7 @@ table_block_parse(struct table_spec *s,
 /*
  * selector.
  *
- * selector SELECTOR_NAME {
- *	group_id FIELD_NAME
- *	selector {
- *		FIELD_NAME
- *		...
- *	}
- *	member_id FIELD_NAME
- *	n_groups N_GROUPS
- *	n_members_per_group N_MEMBERS_PER_GROUP
- * }
  */
-struct selector_spec {
-	char *name;
-	struct rte_swx_pipeline_selector_params params;
-};
-
 static void
 selector_spec_free(struct selector_spec *s)
 {
@@ -1385,31 +1307,7 @@ selector_block_parse(struct selector_spec *s,
 /*
  * learner.
  *
- * learner LEARNER_NAME {
- *	key {
- *		MATCH_FIELD_NAME
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	size SIZE
- *	timeout {
- *		TIMEOUT_IN_SECONDS
- *		...
- *	}
- * }
  */
-struct learner_spec {
-	char *name;
-	struct rte_swx_pipeline_learner_params params;
-	uint32_t size;
-	uint32_t *timeout;
-	uint32_t n_timeouts;
-};
-
 static void
 learner_spec_free(struct learner_spec *s)
 {
@@ -1958,14 +1856,7 @@ learner_block_parse(struct learner_spec *s,
 /*
  * regarray.
  *
- * regarray NAME size SIZE initval INITVAL
  */
-struct regarray_spec {
-	char *name;
-	uint64_t init_val;
-	uint32_t size;
-};
-
 static void
 regarray_spec_free(struct regarray_spec *s)
 {
@@ -2033,13 +1924,7 @@ regarray_statement_parse(struct regarray_spec *s,
 /*
  * metarray.
  *
- * metarray NAME size SIZE
  */
-struct metarray_spec {
-	char *name;
-	uint32_t size;
-};
-
 static void
 metarray_spec_free(struct metarray_spec *s)
 {
@@ -2095,16 +1980,7 @@ metarray_statement_parse(struct metarray_spec *s,
 /*
  * apply.
  *
- * apply {
- *	INSTRUCTION
- *	...
- * }
  */
-struct apply_spec {
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 apply_spec_free(struct apply_spec *s)
 {
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
new file mode 100644
index 0000000000..8458de878a
--- /dev/null
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Intel Corporation
+ */
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_common.h>
+
+#include <rte_swx_pipeline.h>
+
+/*
+ * extobj.
+ *
+ * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
+ */
+struct extobj_spec {
+	char *name;
+	char *extern_type_name;
+	char *pragma;
+};
+
+/*
+ * struct.
+ *
+ * struct STRUCT_TYPE_NAME {
+ *	bit<SIZE> | varbit<SIZE> FIELD_NAME
+ *	...
+ * }
+ */
+struct struct_spec {
+	char *name;
+	struct rte_swx_field_params *fields;
+	uint32_t n_fields;
+	int varbit;
+};
+
+/*
+ * header.
+ *
+ * header HEADER_NAME instanceof STRUCT_TYPE_NAME
+ */
+struct header_spec {
+	char *name;
+	char *struct_type_name;
+};
+
+/*
+ * metadata.
+ *
+ * metadata instanceof STRUCT_TYPE_NAME
+ */
+struct metadata_spec {
+	char *struct_type_name;
+};
+
+/*
+ * action.
+ *
+ * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct action_spec {
+	char *name;
+	char *args_struct_type_name;
+	const char **instructions;
+	uint32_t n_instructions;
+};
+
+/*
+ * table.
+ *
+ * table TABLE_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME exact | wildcard | lpm
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly ]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	instanceof TABLE_TYPE_NAME
+ *	pragma ARGS
+ *	size SIZE
+ * }
+ */
+struct table_spec {
+	char *name;
+	struct rte_swx_pipeline_table_params params;
+	char *recommended_table_type_name;
+	char *args;
+	uint32_t size;
+};
+
+/*
+ * selector.
+ *
+ * selector SELECTOR_NAME {
+ *	group_id FIELD_NAME
+ *	selector {
+ *		FIELD_NAME
+ *		...
+ *	}
+ *	member_id FIELD_NAME
+ *	n_groups N_GROUPS
+ *	n_members_per_group N_MEMBERS_PER_GROUP
+ * }
+ */
+struct selector_spec {
+	char *name;
+	struct rte_swx_pipeline_selector_params params;
+};
+
+/*
+ * learner.
+ *
+ * learner LEARNER_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	size SIZE
+ *	timeout {
+ *		TIMEOUT_IN_SECONDS
+ *		...
+ *	}
+ * }
+ */
+struct learner_spec {
+	char *name;
+	struct rte_swx_pipeline_learner_params params;
+	uint32_t size;
+	uint32_t *timeout;
+	uint32_t n_timeouts;
+};
+
+/*
+ * regarray.
+ *
+ * regarray NAME size SIZE initval INITVAL
+ */
+struct regarray_spec {
+	char *name;
+	uint64_t init_val;
+	uint32_t size;
+};
+
+/*
+ * metarray.
+ *
+ * metarray NAME size SIZE
+ */
+struct metarray_spec {
+	char *name;
+	uint32_t size;
+};
+
+/*
+ * apply.
+ *
+ * apply {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct apply_spec {
+	const char **instructions;
+	uint32_t n_instructions;
+};
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 03/17] pipeline: add pipeline specification data structure
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
                       ` (14 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add specification data structure for the entire pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 21 ++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h | 32 ++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 5e07b4f794..642091b678 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2082,6 +2082,27 @@ apply_block_parse(struct apply_spec *s,
 /*
  * Pipeline.
  */
+void
+pipeline_spec_free(struct pipeline_spec *s)
+{
+	if (!s)
+		return;
+
+	free(s->extobjs);
+	free(s->structs);
+	free(s->headers);
+	free(s->metadata);
+	free(s->actions);
+	free(s->tables);
+	free(s->selectors);
+	free(s->learners);
+	free(s->regarrays);
+	free(s->metarrays);
+	free(s->apply);
+
+	memset(s, 0, sizeof(struct pipeline_spec));
+}
+
 int
 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				 FILE *spec,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 8458de878a..e1170a33b1 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -174,3 +174,35 @@ struct apply_spec {
 	const char **instructions;
 	uint32_t n_instructions;
 };
+
+/*
+ * Pipeline.
+ */
+struct pipeline_spec {
+	struct extobj_spec *extobjs;
+	struct struct_spec *structs;
+	struct header_spec *headers;
+	struct metadata_spec *metadata;
+	struct action_spec *actions;
+	struct table_spec *tables;
+	struct selector_spec *selectors;
+	struct learner_spec *learners;
+	struct regarray_spec *regarrays;
+	struct metarray_spec *metarrays;
+	struct apply_spec *apply;
+
+	uint32_t n_extobjs;
+	uint32_t n_structs;
+	uint32_t n_headers;
+	uint32_t n_metadata;
+	uint32_t n_actions;
+	uint32_t n_tables;
+	uint32_t n_selectors;
+	uint32_t n_learners;
+	uint32_t n_regarrays;
+	uint32_t n_metarrays;
+	uint32_t n_apply;
+};
+
+void
+pipeline_spec_free(struct pipeline_spec *s);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 04/17] pipeline: rework the specification file-based pipeline build
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
                       ` (13 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Rework the specification file-based pipeline build operation to first
parse the specification file into the previously introduced pipeline
specification data structure, then use this structure to configure
and build the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 478 +++++++++++++++++++++------
 lib/pipeline/rte_swx_pipeline_spec.h |   9 +
 2 files changed, 385 insertions(+), 102 deletions(-)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 642091b678..62929a9da6 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2103,11 +2103,10 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg)
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg)
 {
 	struct extobj_spec extobj_spec = {0};
 	struct struct_spec struct_spec = {0};
@@ -2120,26 +2119,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	struct regarray_spec regarray_spec = {0};
 	struct metarray_spec metarray_spec = {0};
 	struct apply_spec apply_spec = {0};
-	uint32_t n_lines;
+	struct pipeline_spec *s = NULL;
+	uint32_t n_lines = 0;
 	uint32_t block_mask = 0;
-	int status;
+	int status = 0;
 
 	/* Check the input arguments. */
-	if (!p) {
+	if (!spec) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null pipeline argument.";
+			*err_msg = "Invalid input argument.";
 		status = -EINVAL;
 		goto error;
 	}
 
-	if (!spec) {
+	/* Memory allocation. */
+	s = calloc(sizeof(struct pipeline_spec), 1);
+	if (!s) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null specification file argument.";
-		status = -EINVAL;
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
 		goto error;
 	}
 
@@ -2200,6 +2202,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* struct block. */
 		if (block_mask & (1 << STRUCT_BLOCK)) {
+			struct struct_spec *new_structs;
+
 			status = struct_block_parse(&struct_spec,
 						    &block_mask,
 						    tokens,
@@ -2214,26 +2218,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_struct_type_register(p,
-				struct_spec.name,
-				struct_spec.fields,
-				struct_spec.n_fields,
-				struct_spec.varbit);
-			if (status) {
+			new_structs = realloc(s->structs,
+					      (s->n_structs + 1) * sizeof(struct struct_spec));
+			if (!new_structs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Struct registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			struct_spec_free(&struct_spec);
+			s->structs = new_structs;
+			memcpy(&s->structs[s->n_structs], &struct_spec, sizeof(struct struct_spec));
+			s->n_structs++;
+			memset(&struct_spec, 0, sizeof(struct struct_spec));
 
 			continue;
 		}
 
 		/* action block. */
 		if (block_mask & (1 << ACTION_BLOCK)) {
+			struct action_spec *new_actions;
+
 			status = action_block_parse(&action_spec,
 						    &block_mask,
 						    tokens,
@@ -2248,26 +2255,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_action_config(p,
-				action_spec.name,
-				action_spec.args_struct_type_name,
-				action_spec.instructions,
-				action_spec.n_instructions);
-			if (status) {
+			new_actions = realloc(s->actions,
+					      (s->n_actions + 1) * sizeof(struct action_spec));
+			if (!new_actions) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Action config error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			action_spec_free(&action_spec);
+			s->actions = new_actions;
+			memcpy(&s->actions[s->n_actions], &action_spec, sizeof(struct action_spec));
+			s->n_actions++;
+			memset(&action_spec, 0, sizeof(struct action_spec));
 
 			continue;
 		}
 
 		/* table block. */
 		if (block_mask & (1 << TABLE_BLOCK)) {
+			struct table_spec *new_tables;
+
 			status = table_block_parse(&table_spec,
 						   &block_mask,
 						   tokens,
@@ -2282,27 +2292,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_table_config(p,
-				table_spec.name,
-				&table_spec.params,
-				table_spec.recommended_table_type_name,
-				table_spec.args,
-				table_spec.size);
-			if (status) {
+			new_tables = realloc(s->tables,
+					     (s->n_tables + 1) * sizeof(struct table_spec));
+			if (!new_tables) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			table_spec_free(&table_spec);
+			s->tables = new_tables;
+			memcpy(&s->tables[s->n_tables], &table_spec, sizeof(struct table_spec));
+			s->n_tables++;
+			memset(&table_spec, 0, sizeof(struct table_spec));
 
 			continue;
 		}
 
 		/* selector block. */
 		if (block_mask & (1 << SELECTOR_BLOCK)) {
+			struct selector_spec *new_selectors;
+
 			status = selector_block_parse(&selector_spec,
 						      &block_mask,
 						      tokens,
@@ -2317,24 +2329,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_selector_config(p,
-				selector_spec.name,
-				&selector_spec.params);
-			if (status) {
+			new_selectors = realloc(s->selectors,
+				(s->n_selectors + 1) * sizeof(struct selector_spec));
+			if (!new_selectors) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Selector configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			selector_spec_free(&selector_spec);
+			s->selectors = new_selectors;
+			memcpy(&s->selectors[s->n_selectors],
+			       &selector_spec,
+			       sizeof(struct selector_spec));
+			s->n_selectors++;
+			memset(&selector_spec, 0, sizeof(struct selector_spec));
 
 			continue;
 		}
 
 		/* learner block. */
 		if (block_mask & (1 << LEARNER_BLOCK)) {
+			struct learner_spec *new_learners;
+
 			status = learner_block_parse(&learner_spec,
 						     &block_mask,
 						     tokens,
@@ -2349,27 +2368,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_learner_config(p,
-				learner_spec.name,
-				&learner_spec.params,
-				learner_spec.size,
-				learner_spec.timeout,
-				learner_spec.n_timeouts);
-			if (status) {
+			new_learners = realloc(s->learners,
+					       (s->n_learners + 1) * sizeof(struct learner_spec));
+			if (!new_learners) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Learner table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			learner_spec_free(&learner_spec);
+			s->learners = new_learners;
+			memcpy(&s->learners[s->n_learners],
+			       &learner_spec,
+			       sizeof(struct learner_spec));
+			s->n_learners++;
+			memset(&learner_spec, 0, sizeof(struct learner_spec));
 
 			continue;
 		}
 
 		/* apply block. */
 		if (block_mask & (1 << APPLY_BLOCK)) {
+			struct apply_spec *new_apply;
+
 			status = apply_block_parse(&apply_spec,
 						   &block_mask,
 						   tokens,
@@ -2384,24 +2407,28 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_instructions_config(p,
-				apply_spec.instructions,
-				apply_spec.n_instructions);
-			if (status) {
+			new_apply = realloc(s->apply, (s->n_apply + 1) * sizeof(struct apply_spec));
+			if (!new_apply) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Pipeline instructions err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			apply_spec_free(&apply_spec);
+			s->apply = new_apply;
+			memcpy(&s->apply[s->n_apply], &apply_spec, sizeof(struct apply_spec));
+			s->n_apply++;
+			memset(&apply_spec, 0, sizeof(struct apply_spec));
 
 			continue;
 		}
 
 		/* extobj. */
 		if (!strcmp(tokens[0], "extobj")) {
+			struct extobj_spec *new_extobjs;
+
 			status = extobj_statement_parse(&extobj_spec,
 							tokens,
 							n_tokens,
@@ -2411,19 +2438,21 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_extern_object_config(p,
-				extobj_spec.name,
-				extobj_spec.extern_type_name,
-				extobj_spec.pragma);
-			if (status) {
+			new_extobjs = realloc(s->extobjs,
+					      (s->n_extobjs + 1) * sizeof(struct extobj_spec));
+			if (!new_extobjs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Extern object config err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			extobj_spec_free(&extobj_spec);
+			s->extobjs = new_extobjs;
+			memcpy(&s->extobjs[s->n_extobjs], &extobj_spec, sizeof(struct extobj_spec));
+			s->n_extobjs++;
+			memset(&extobj_spec, 0, sizeof(struct extobj_spec));
 
 			continue;
 		}
@@ -2445,6 +2474,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* header. */
 		if (!strcmp(tokens[0], "header")) {
+			struct header_spec *new_headers;
+
 			status = header_statement_parse(&header_spec,
 							tokens,
 							n_tokens,
@@ -2454,24 +2485,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_header_register(p,
-				header_spec.name,
-				header_spec.struct_type_name);
-			if (status) {
+			new_headers = realloc(s->headers,
+					      (s->n_headers + 1) * sizeof(struct header_spec));
+			if (!new_headers) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Header registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			header_spec_free(&header_spec);
+			s->headers = new_headers;
+			memcpy(&s->headers[s->n_headers], &header_spec, sizeof(struct header_spec));
+			s->n_headers++;
+			memset(&header_spec, 0, sizeof(struct header_spec));
 
 			continue;
 		}
 
 		/* metadata. */
 		if (!strcmp(tokens[0], "metadata")) {
+			struct metadata_spec *new_metadata;
+
 			status = metadata_statement_parse(&metadata_spec,
 							  tokens,
 							  n_tokens,
@@ -2481,17 +2517,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_metadata_register(p,
-				metadata_spec.struct_type_name);
-			if (status) {
+			new_metadata = realloc(s->metadata,
+					       (s->n_metadata + 1) * sizeof(struct metadata_spec));
+			if (!new_metadata) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meta-data reg err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metadata_spec_free(&metadata_spec);
+			s->metadata = new_metadata;
+			memcpy(&s->metadata[s->n_metadata],
+			       &metadata_spec,
+			       sizeof(struct metadata_spec));
+			s->n_metadata++;
+			memset(&metadata_spec, 0, sizeof(struct metadata_spec));
 
 			continue;
 		}
@@ -2558,6 +2600,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* regarray. */
 		if (!strcmp(tokens[0], "regarray")) {
+			struct regarray_spec *new_regarrays;
+
 			status = regarray_statement_parse(&regarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2567,25 +2611,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_regarray_config(p,
-				regarray_spec.name,
-				regarray_spec.size,
-				regarray_spec.init_val);
-			if (status) {
+			new_regarrays = realloc(s->regarrays,
+				(s->n_regarrays + 1) * sizeof(struct regarray_spec));
+			if (!new_regarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Register array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			regarray_spec_free(&regarray_spec);
+			s->regarrays = new_regarrays;
+			memcpy(&s->regarrays[s->n_regarrays],
+			       &regarray_spec,
+			       sizeof(struct regarray_spec));
+			s->n_regarrays++;
+			memset(&regarray_spec, 0, sizeof(struct regarray_spec));
 
 			continue;
 		}
 
 		/* metarray. */
 		if (!strcmp(tokens[0], "metarray")) {
+			struct metarray_spec *new_metarrays;
+
 			status = metarray_statement_parse(&metarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2595,18 +2645,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_metarray_config(p,
-				metarray_spec.name,
-				metarray_spec.size);
-			if (status) {
+			new_metarrays = realloc(s->metarrays,
+				(s->n_metarrays + 1) * sizeof(struct metarray_spec));
+			if (!new_metarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meter array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metarray_spec_free(&metarray_spec);
+			s->metarrays = new_metarrays;
+			memcpy(&s->metarrays[s->n_metarrays],
+			       &metarray_spec,
+			       sizeof(struct metarray_spec));
+			s->n_metarrays++;
+			memset(&metarray_spec, 0, sizeof(struct metarray_spec));
 
 			continue;
 		}
@@ -2644,17 +2699,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 		goto error;
 	}
 
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = n_lines;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
+	return s;
 
 error:
 	extobj_spec_free(&extobj_spec);
@@ -2668,5 +2713,234 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	regarray_spec_free(&regarray_spec);
 	metarray_spec_free(&metarray_spec);
 	apply_spec_free(&apply_spec);
+	pipeline_spec_free(s);
+
+	return NULL;
+}
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg)
+{
+	uint32_t i;
+	int status = 0;
+
+	/* extobj. */
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		status = rte_swx_pipeline_extern_object_config(p,
+			extobj_spec->name,
+			extobj_spec->extern_type_name,
+			extobj_spec->pragma);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Extern object configuration error.";
+			return status;
+		}
+	}
+
+	/* regarray. */
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		status = rte_swx_pipeline_regarray_config(p,
+			regarray_spec->name,
+			regarray_spec->size,
+			regarray_spec->init_val);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Register array configuration error.";
+			return status;
+		}
+	}
+
+	/* metarray. */
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		status = rte_swx_pipeline_metarray_config(p,
+			metarray_spec->name,
+			metarray_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meter array configuration error.";
+			return status;
+		}
+	}
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		status = rte_swx_pipeline_struct_type_register(p,
+			struct_spec->name,
+			struct_spec->fields,
+			struct_spec->n_fields,
+			struct_spec->varbit);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Struct type registration error.";
+			return status;
+		}
+	}
+
+	/* header. */
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		status = rte_swx_pipeline_packet_header_register(p,
+			header_spec->name,
+			header_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Header configuration error.";
+			return status;
+		}
+	}
+
+	/* metadata. */
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		status = rte_swx_pipeline_packet_metadata_register(p,
+			metadata_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meta-data registration error.";
+			return status;
+		}
+	}
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		status = rte_swx_pipeline_action_config(p,
+			action_spec->name,
+			action_spec->args_struct_type_name,
+			action_spec->instructions,
+			action_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Action configuration error.";
+			return status;
+		}
+	}
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		status = rte_swx_pipeline_table_config(p,
+			table_spec->name,
+			&table_spec->params,
+			table_spec->recommended_table_type_name,
+			table_spec->args,
+			table_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Table configuration error.";
+			return status;
+		}
+	}
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		status = rte_swx_pipeline_selector_config(p,
+			selector_spec->name,
+			&selector_spec->params);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Selector table configuration error.";
+			return status;
+		}
+	}
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		status = rte_swx_pipeline_learner_config(p,
+			learner_spec->name,
+			&learner_spec->params,
+			learner_spec->size,
+			learner_spec->timeout,
+			learner_spec->n_timeouts);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Learner table configuration error.";
+			return status;
+		}
+	}
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+
+		status = rte_swx_pipeline_instructions_config(p,
+			apply_spec->instructions,
+			apply_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline instructions configuration error.";
+			return status;
+		}
+	}
+
+	return 0;
+}
+
+int
+rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
+				 FILE *spec_file,
+				 uint32_t *err_line,
+				 const char **err_msg)
+{
+	struct pipeline_spec *s = NULL;
+	int status = 0;
+
+	/* Check the input arguments. */
+	if (!p || !spec_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Spec file parse. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Pipeline configure. */
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto error;
+	}
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline build error.";
+		goto error;
+	}
+
+	return 0;
+
+error:
+	pipeline_spec_free(s);
 	return status;
 }
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index e1170a33b1..4f3a0b5958 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,3 +206,12 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg);
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 05/17] pipeline: generate the code for pipeline specification structure
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (2 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
                       ` (12 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add support to export the pipeline specification data structure to a C
source code file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 622 +++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h |   5 +
 2 files changed, 627 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 62929a9da6..bf21fe17ba 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2020 Intel Corporation
  */
 #include <stdint.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -2103,6 +2104,627 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
+static const char *
+match_type_string_get(enum rte_swx_table_match_type match_type)
+{
+	switch (match_type) {
+	case RTE_SWX_TABLE_MATCH_WILDCARD: return "RTE_SWX_TABLE_MATCH_WILDCARD";
+	case RTE_SWX_TABLE_MATCH_LPM: return "RTE_SWX_TABLE_MATCH_LPM";
+	case RTE_SWX_TABLE_MATCH_EXACT: return "RTE_SWX_TABLE_MATCH_EXACT";
+	default: return "RTE_SWX_TABLE_MATCH_UNKNOWN";
+	}
+}
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s)
+{
+	uint32_t i;
+
+	/* Check the input arguments. */
+	if (!f || !s)
+		return;
+
+	/* extobj. */
+	fprintf(f, "static struct extobj_spec extobjs[] = {\n");
+
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", extobj_spec->name);
+		fprintf(f, "\t\t.extern_type_name = \"%s\",\n", extobj_spec->extern_type_name);
+		if (extobj_spec->pragma)
+			fprintf(f, "\t\t.pragma = \"%s\",\n", extobj_spec->pragma);
+		else
+			fprintf(f, "\t\t.pragma = NULL,\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* regarray. */
+	fprintf(f, "static struct regarray_spec regarrays[] = {\n");
+
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", regarray_spec->name);
+		fprintf(f, "\t\t.init_val = %" PRIu64 ",\n", regarray_spec->init_val);
+		fprintf(f, "\t\t.size = %u,\n", regarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metarray. */
+	fprintf(f, "static struct metarray_spec metarrays[] = {\n");
+
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", metarray_spec->name);
+		fprintf(f, "\t\t.size = %u,\n", metarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+		uint32_t j;
+
+		fprintf(f, "static struct rte_swx_field_params struct_%s_fields[] = {\n",
+			struct_spec->name);
+
+		for (j = 0; j < struct_spec->n_fields; j++) {
+			struct rte_swx_field_params *field = &struct_spec->fields[j];
+
+			fprintf(f, "\t[%d] = {\n", j);
+			fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+			fprintf(f, "\t\t.n_bits = %u,\n", field->n_bits);
+			fprintf(f, "\t},\n");
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct struct_spec structs[] = {\n");
+
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", struct_spec->name);
+		fprintf(f, "\t\t.fields = struct_%s_fields,\n", struct_spec->name);
+		fprintf(f, "\t\t.n_fields = "
+			"sizeof(struct_%s_fields) / sizeof(struct_%s_fields[0]),\n",
+			struct_spec->name,
+			struct_spec->name);
+		fprintf(f, "\t\t.varbit = %d,\n", struct_spec->varbit);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* header. */
+	fprintf(f, "static struct header_spec headers[] = {\n");
+
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", header_spec->name);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", header_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metadata. */
+	fprintf(f, "static struct metadata_spec metadata[] = {\n");
+
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", metadata_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *action_%s_initial_instructions[] = {\n",
+			action_spec->name);
+
+		for (j = 0; j < action_spec->n_instructions; j++) {
+			const char *instr = action_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct action_spec actions[] = {\n");
+
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", action_spec->name);
+
+		if (action_spec->args_struct_type_name)
+			fprintf(f, "\t\t.args_struct_type_name = \"%s\",\n",
+				action_spec->args_struct_type_name);
+		else
+			fprintf(f, "\t\t.args_struct_type_name = NULL,\n");
+
+		fprintf(f, "\t\t.instructions = action_%s_initial_instructions,\n",
+			action_spec->name);
+		fprintf(f, "\t\t.n_instructions = "
+			"sizeof(action_%s_initial_instructions) / "
+			"sizeof(action_%s_initial_instructions[0]),\n",
+			action_spec->name,
+			action_spec->name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+		uint32_t j;
+
+		/* fields. */
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "static struct rte_swx_match_field_params "
+				"table_%s_fields[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_fields; j++) {
+				struct rte_swx_match_field_params *field =
+					&table_spec->params.fields[j];
+
+				fprintf(f, "\t[%d] = {\n", j);
+				fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+				fprintf(f, "\t\t.match_type = %s,\n",
+					match_type_string_get(field->match_type));
+				fprintf(f, "\t},\n");
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (table_spec->params.action_names && table_spec->params.n_actions) {
+			fprintf(f, "static const char *table_%s_action_names[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				const char *action_name = table_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (table_spec->params.action_is_for_table_entries &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_table_entries[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (table_spec->params.action_is_for_default_entry &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_default_entry[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct table_spec tables[] = {\n");
+
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", table_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.fields = table_%s_fields,\n", table_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(table_%s_fields) / sizeof(table_%s_fields[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.fields = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (table_spec->params.action_names && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = table_%s_action_names,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (table_spec->params.action_is_for_table_entries && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"table_%s_action_is_for_table_entries,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (table_spec->params.action_is_for_default_entry && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"table_%s_action_is_for_default_entry,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = sizeof(table_%s_action_names) / "
+				"sizeof(table_%s_action_names[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = 0,\n");
+
+		if (table_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				table_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (table_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				table_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			table_spec->params.default_action_is_const);
+		fprintf(f, "\t\t},\n");
+
+		if (table_spec->recommended_table_type_name)
+			fprintf(f, "\t\t.recommended_table_type_name = \"%s\",\n",
+				table_spec->recommended_table_type_name);
+		else
+			fprintf(f, "\t\t.recommended_table_type_name = NULL,\n");
+
+		if (table_spec->args)
+			fprintf(f, "\t\t.args = \"%s\",\n", table_spec->args);
+		else
+			fprintf(f, "\t\t.args = NULL,\n");
+
+		fprintf(f, "\t\t.size = %u,\n", table_spec->size);
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+		uint32_t j;
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "static const char *selector_%s_field_names[] = {\n",
+				selector_spec->name);
+
+			for (j = 0; j < selector_spec->params.n_selector_fields; j++) {
+				const char *field_name =
+					selector_spec->params.selector_field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct selector_spec selectors[] = {\n");
+
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+
+		fprintf(f, "\t\t.name = \"%s\",\n", selector_spec->name);
+		fprintf(f, "\t\t.params = {\n");
+
+		if (selector_spec->params.group_id_field_name)
+			fprintf(f, "\t\t\t.group_id_field_name = \"%s\",\n",
+				selector_spec->params.group_id_field_name);
+		else
+			fprintf(f, "\t\t\t.group_id_field_name = NULL,\n");
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "\t\t\t.selector_field_names = selector_%s_field_names,\n",
+				selector_spec->name);
+			fprintf(f, "\t\t\t.n_selector_fields = "
+				"sizeof(selector_%s_field_names) / sizeof(selector_%s_field_names[0]),\n",
+				selector_spec->name,
+				selector_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.selector_field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_selector_fields = 0,\n");
+		}
+
+		if (selector_spec->params.member_id_field_name)
+			fprintf(f, "\t\t\t.member_id_field_name = \"%s\",\n",
+				selector_spec->params.member_id_field_name);
+		else
+			fprintf(f, "\t\t\t.member_id_field_name = NULL,\n");
+
+		fprintf(f, "\t\t\t.n_groups_max = %u,\n", selector_spec->params.n_groups_max);
+
+		fprintf(f, "\t\t\t.n_members_per_group_max = %u,\n",
+			selector_spec->params.n_members_per_group_max);
+
+		fprintf(f, "\t\t},\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+		uint32_t j;
+
+		/* field_names. */
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "static const char *learner_%s_field_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_fields; j++) {
+				const char *field_name = learner_spec->params.field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (learner_spec->params.action_names && learner_spec->params.n_actions) {
+			fprintf(f, "static const char *learner_%s_action_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				const char *action_name = learner_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_table_entries[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_default_entry[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* timeout. */
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "static uint32_t learner_%s_timeout[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->n_timeouts; j++) {
+				uint32_t value = learner_spec->timeout[j];
+
+				fprintf(f, "\t[%d] = %u,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct learner_spec learners[] = {\n");
+
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", learner_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.field_names = learner_%s_field_names,\n",
+				learner_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(learner_%s_field_names) / "
+				"sizeof(learner_%s_field_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = learner_%s_action_names,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"learner_%s_action_is_for_table_entries,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"learner_%s_action_is_for_default_entry,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = "
+				"sizeof(learner_%s_action_names) / sizeof(learner_%s_action_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = NULL,\n");
+
+		if (learner_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				learner_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (learner_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				learner_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			learner_spec->params.default_action_is_const);
+
+		fprintf(f, "\t\t},\n");
+
+		fprintf(f, "\t\t.size = %u,\n", learner_spec->size);
+
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "\t\t.timeout = learner_%s_timeout,\n", learner_spec->name);
+			fprintf(f, "\t\t\t.n_timeouts = "
+				"sizeof(learner_%s_timeout) / sizeof(learner_%s_timeout[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t.timeout = NULL,\n");
+			fprintf(f, "\t\t\t.n_timeouts = 0,\n");
+		}
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *apply%u_initial_instructions[] = {\n", i);
+
+		for (j = 0; j < apply_spec->n_instructions; j++) {
+			const char *instr = apply_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct apply_spec apply[] = {\n");
+
+	for (i = 0; i < s->n_apply; i++) {
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t.instructions = apply%u_initial_instructions,\n", i);
+		fprintf(f, "\t.n_instructions = "
+			"sizeof(apply%u_initial_instructions) / "
+			"sizeof(apply%u_initial_instructions[0]),\n",
+			i,
+			i);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* pipeline. */
+	fprintf(f, "struct pipeline_spec pipeline_spec = {\n");
+	fprintf(f, "\t.extobjs = extobjs,\n");
+	fprintf(f, "\t.structs = structs,\n");
+	fprintf(f, "\t.headers = headers,\n");
+	fprintf(f, "\t.metadata = metadata,\n");
+	fprintf(f, "\t.actions = actions,\n");
+	fprintf(f, "\t.tables = tables,\n");
+	fprintf(f, "\t.selectors = selectors,\n");
+	fprintf(f, "\t.learners = learners,\n");
+	fprintf(f, "\t.regarrays = regarrays,\n");
+	fprintf(f, "\t.metarrays = metarrays,\n");
+	fprintf(f, "\t.apply = apply,\n");
+	fprintf(f, "\t.n_extobjs = sizeof(extobjs) / sizeof(extobjs[0]),\n");
+	fprintf(f, "\t.n_structs = sizeof(structs) / sizeof(structs[0]),\n");
+	fprintf(f, "\t.n_headers = sizeof(headers) / sizeof(headers[0]),\n");
+	fprintf(f, "\t.n_metadata = sizeof(metadata) / sizeof(metadata[0]),\n");
+	fprintf(f, "\t.n_actions = sizeof(actions) / sizeof(actions[0]),\n");
+	fprintf(f, "\t.n_tables = sizeof(tables) / sizeof(tables[0]),\n");
+	fprintf(f, "\t.n_selectors = sizeof(selectors) / sizeof(selectors[0]),\n");
+	fprintf(f, "\t.n_learners = sizeof(learners) / sizeof(learners[0]),\n");
+	fprintf(f, "\t.n_regarrays = sizeof(regarrays) / sizeof(regarrays[0]),\n");
+	fprintf(f, "\t.n_metarrays = sizeof(metarrays) / sizeof(metarrays[0]),\n");
+	fprintf(f, "\t.n_apply = sizeof(apply) / sizeof(apply[0]),\n");
+	fprintf(f, "};\n");
+}
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 4f3a0b5958..707b99ba09 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,6 +206,11 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s);
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 06/17] pipeline: add support for pipeline I/O specification
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (3 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
                       ` (11 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add specification data structure and API for the pipeline I/O ports
and related pipeline configuration such as packet mirroring.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 852 +++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h |  58 ++
 2 files changed, 910 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index bf21fe17ba..89cf194b19 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -9,6 +9,12 @@
 #include <errno.h>
 
 #include <rte_common.h>
+#include <rte_mempool.h>
+
+#include <rte_swx_port_ethdev.h>
+#include <rte_swx_port_ring.h>
+#include <rte_swx_port_source_sink.h>
+#include <rte_swx_port_fd.h>
 
 #include "rte_swx_pipeline_spec.h"
 
@@ -3566,3 +3572,849 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	pipeline_spec_free(s);
 	return status;
 }
+
+static void
+port_in_params_free(void *params, const char *port_type)
+{
+	uintptr_t dev_name;
+
+	if (!params || !port_type)
+		return;
+
+	if (!strcmp(port_type, "ethdev")) {
+		struct rte_swx_port_ethdev_reader_params *p = params;
+
+		dev_name = (uintptr_t)p->dev_name;
+	} else if (!strcmp(port_type, "ring")) {
+		struct rte_swx_port_ring_reader_params *p = params;
+
+		dev_name = (uintptr_t)p->name;
+	} else if (!strcmp(port_type, "source")) {
+		struct rte_swx_port_source_params *p = params;
+
+		dev_name = (uintptr_t)p->file_name;
+	} else
+		dev_name = (uintptr_t)NULL;
+
+	free((void *)dev_name);
+	free(params);
+}
+
+static void
+port_out_params_free(void *params, const char *port_type)
+{
+	uintptr_t dev_name;
+
+	if (!params || !port_type)
+		return;
+
+	if (!strcmp(port_type, "ethdev")) {
+		struct rte_swx_port_ethdev_writer_params *p = params;
+
+		dev_name = (uintptr_t)p->dev_name;
+	} else if (!strcmp(port_type, "ring")) {
+		struct rte_swx_port_ring_writer_params *p = params;
+
+		dev_name = (uintptr_t)p->name;
+	} else if (!strcmp(port_type, "sink")) {
+		struct rte_swx_port_sink_params *p = params;
+
+		dev_name = (uintptr_t)p->file_name;
+	} else
+		dev_name = (uintptr_t)NULL;
+
+	free((void *)dev_name);
+	free(params);
+}
+
+void
+pipeline_iospec_free(struct pipeline_iospec *s)
+{
+	uint32_t i;
+
+	if (!s)
+		return;
+
+	/* Input ports. */
+	for (i = 0; i < s->n_ports_in; i++) {
+		uintptr_t name = (uintptr_t)s->port_in_type[i];
+
+		port_in_params_free(s->port_in_params[i], s->port_in_type[i]);
+		free((void *)name);
+	}
+
+	free(s->port_in_type);
+	free(s->port_in_params);
+
+	/* Output ports. */
+	for (i = 0; i < s->n_ports_out; i++) {
+		uintptr_t name = (uintptr_t)s->port_out_type[i];
+
+		port_out_params_free(s->port_out_params[i], s->port_out_type[i]);
+		free((void *)name);
+	}
+
+	free(s->port_out_type);
+	free(s->port_out_params);
+
+	free(s);
+}
+
+static int
+mirroring_parse(struct rte_swx_pipeline_mirroring_params *p,
+		char **tokens,
+		uint32_t n_tokens,
+		const char **err_msg)
+{
+	char *token;
+
+	if ((n_tokens != 4) || strcmp(tokens[0], "slots") || strcmp(tokens[2], "sessions")) {
+		if (err_msg)
+		    *err_msg = "Invalid statement.";
+		return -EINVAL;
+	}
+
+	/* <n_slots>. */
+	token = tokens[1];
+	p->n_slots = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <n_slots> parameter.";
+		return -EINVAL;
+	}
+
+	/* <n_sessions>. */
+	token = tokens[3];
+	p->n_sessions = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <n_sessions> parameter.";
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+port_in_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ethdev_reader_params *p = NULL;
+	char *token, *dev_name = NULL;
+	uint32_t queue_id, burst_size;
+
+	if ((n_tokens != 5) || strcmp(tokens[1], "rxq") || strcmp(tokens[3], "bsz")) {
+		if (err_msg)
+		    *err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <queue_id>. */
+	token = tokens[2];
+	queue_id = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <queue_id> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[4];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	dev_name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ethdev_reader_params));
+	if (!dev_name || !p) {
+		free(dev_name);
+		free(p);
+
+		if (err_msg)
+		    *err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->dev_name = dev_name;
+	p->queue_id = queue_id;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_in_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ring_reader_params *p = NULL;
+	char *token, *name = NULL;
+	uint32_t burst_size;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+		    *err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ring_reader_params));
+	if (!name || !p) {
+		free(name);
+		free(p);
+
+		if (err_msg)
+		    *err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->name = name;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_in_source_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_source_params *p = NULL;
+	struct rte_mempool *pool = NULL;
+	char *token, *file_name = NULL;
+	uint32_t n_loops, n_pkts_max;
+
+	if ((n_tokens != 8) ||
+	    strcmp(tokens[0], "mempool") ||
+	    strcmp(tokens[2], "file") ||
+	    strcmp(tokens[4], "loop") ||
+	    strcmp(tokens[6], "packets")) {
+		if (err_msg)
+		    *err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <mempool_name>. */
+	pool = rte_mempool_lookup(tokens[1]);
+	if (!pool) {
+		if (err_msg)
+		    *err_msg = "Invalid <mempool_name> parameter.";
+		return NULL;
+	}
+
+	/* <n_loops>. */
+	token = tokens[5];
+	n_loops = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <n_loops> parameter.";
+		return NULL;
+	}
+
+	/* <n_pkts_max>. */
+	token = tokens[7];
+	n_pkts_max = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <n_pkts_max> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	file_name = strdup(tokens[3]);
+	p = malloc(sizeof(struct rte_swx_port_source_params));
+	if (!file_name || !p) {
+		free(file_name);
+		free(p);
+
+		if (err_msg)
+		    *err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->pool = pool;
+	p->file_name = file_name;
+	p->n_loops = n_loops;
+	p->n_pkts_max = n_pkts_max;
+
+	return p;
+}
+
+static void *
+port_in_fd_parse(char **tokens,
+		 uint32_t n_tokens,
+		 const char **err_msg)
+{
+	struct rte_swx_port_fd_reader_params *p = NULL;
+	struct rte_mempool *mempool = NULL;
+	char *token;
+	uint32_t mtu, burst_size;
+	int fd;
+
+	if ((n_tokens != 7) ||
+	    strcmp(tokens[1], "mtu") ||
+	    strcmp(tokens[3], "mempool") ||
+	    strcmp(tokens[5], "bsz")) {
+		if (err_msg)
+		    *err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <file_descriptor>. */
+	token = tokens[0];
+	fd = strtol(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <file_descriptor> parameter.";
+		return NULL;
+	}
+
+	/* <mtu>. */
+	token = tokens[2];
+	mtu = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <mtu> parameter.";
+		return NULL;
+	}
+
+	/* <mempool_name>. */
+	mempool = rte_mempool_lookup(tokens[4]);
+	if (!mempool) {
+		if (err_msg)
+		    *err_msg = "Invalid <mempool_name> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[6];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	p = malloc(sizeof(struct rte_swx_port_fd_reader_params));
+	if (!p) {
+		if (err_msg)
+		    *err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->fd = fd;
+	p->mtu = mtu;
+	p->mempool = mempool;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ethdev_writer_params *p = NULL;
+	char *token, *dev_name = NULL;
+	uint32_t queue_id, burst_size;
+
+	if ((n_tokens != 5) || strcmp(tokens[1], "txq") || strcmp(tokens[3], "bsz")) {
+		if (err_msg)
+		    *err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <queue_id>. */
+	token = tokens[2];
+	queue_id = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <queue_id> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[4];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	dev_name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ethdev_writer_params));
+	if (!dev_name || !p) {
+		free(dev_name);
+		free(p);
+
+		if (err_msg)
+		    *err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->dev_name = dev_name;
+	p->queue_id = queue_id;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ring_writer_params *p = NULL;
+	char *token, *name = NULL;
+	uint32_t burst_size;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+		    *err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
+	if (!name || !p) {
+		free(name);
+		free(p);
+
+		if (err_msg)
+		    *err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->name = name;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_sink_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_sink_params *p = NULL;
+	char *file_name = NULL;
+	int file_name_valid = 0;
+
+	if ((n_tokens != 2) || strcmp(tokens[0], "file")){
+		if (err_msg)
+		    *err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	if (strcmp(tokens[1], "none")) {
+		file_name_valid = 1;
+		file_name = strdup(tokens[1]);
+	}
+
+	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
+	if ((file_name_valid && !file_name) || !p) {
+		free(file_name);
+		free(p);
+
+		if (err_msg)
+		    *err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->file_name = file_name;
+
+	return p;
+}
+
+static void *
+port_out_fd_parse(char **tokens,
+		  uint32_t n_tokens,
+		  const char **err_msg)
+{
+	struct rte_swx_port_fd_writer_params *p = NULL;
+	char *token;
+	uint32_t burst_size;
+	int fd;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+		    *err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <file_descriptor>. */
+	token = tokens[0];
+	fd = strtol(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <file_descriptor> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+		    *err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	p = malloc(sizeof(struct rte_swx_port_fd_writer_params));
+	if (!p) {
+		if (err_msg)
+		    *err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->fd = fd;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+struct pipeline_iospec *
+pipeline_iospec_parse(FILE *spec,
+		      uint32_t *err_line,
+		      const char **err_msg)
+{
+	struct pipeline_iospec *s = NULL;
+	uint32_t n_lines = 0;
+
+	/* Check the input arguments. */
+	if (!spec) {
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		goto error;
+	}
+
+	/* Memory allocation. */
+	s = calloc(sizeof(struct pipeline_iospec), 1);
+	if (!s) {
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		goto error;
+	}
+
+	/* Initialize with the defaut values. */
+	s->mirroring_params.n_slots = RTE_SWX_PACKET_MIRRORING_SLOTS_DEFAULT;
+	s->mirroring_params.n_sessions = RTE_SWX_PACKET_MIRRORING_SESSIONS_DEFAULT;
+
+	for (n_lines = 1; ; n_lines++) {
+		char line[MAX_LINE_LENGTH];
+		char *tokens[MAX_TOKENS], *ptr = line;
+		uint32_t n_tokens = 0;
+
+		/* Read next line. */
+		if (!fgets(line, sizeof(line), spec))
+			break;
+
+		/* Parse the line into tokens. */
+		for ( ; ; ) {
+			char *token;
+
+			/* Get token. */
+			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
+			if (!token)
+				break;
+
+			/* Handle comments. */
+			if ((token[0] == '#') ||
+			    (token[0] == ';') ||
+			    ((token[0] == '/') && (token[1] == '/'))) {
+				break;
+			}
+
+			/* Handle excessively long lines. */
+			if (n_tokens >= RTE_DIM(tokens)) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Too many tokens.";
+				goto error;
+			}
+
+			/* Handle excessively long tokens. */
+			if (strnlen(token, RTE_SWX_NAME_SIZE) >=
+			    RTE_SWX_NAME_SIZE) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Token too big.";
+				goto error;
+			}
+
+			/* Save token. */
+			tokens[n_tokens] = token;
+			n_tokens++;
+		}
+
+		/* Handle empty lines. */
+		if (!n_tokens)
+			continue;
+
+		/* mirroring. */
+		if ((n_tokens >= 1) && !strcmp(tokens[0], "mirroring")) {
+			int status = 0;
+
+			status = mirroring_parse(&s->mirroring_params,
+						 &tokens[1],
+						 n_tokens - 1,
+						 err_msg);
+			if (status) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			continue;
+		}
+
+		/* port in. */
+		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "in")) {
+			char *token = tokens[2];
+			uint32_t *new_id = NULL;
+			const char **new_type = NULL, *port_type = NULL;
+			void **new_params = NULL, *p = NULL;
+			uint32_t port_id;
+
+			/* <port_id>. */
+			port_id = strtoul(token, &token, 0);
+			if (token[0]) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Invalid port ID.";
+				goto error;
+			}
+
+			/* <port_type>. */
+			if (!strcmp(tokens[3], "ethdev"))
+				p = port_in_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "ring"))
+				p = port_in_ring_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "source"))
+				p = port_in_source_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "fd"))
+				p = port_in_fd_parse(&tokens[4], n_tokens - 4, err_msg);
+			else {
+				p = NULL;
+				if (err_msg)
+					*err_msg = "Invalid port type.";
+			}
+
+			if (!p) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			/* New port. */
+			port_type = strdup(tokens[3]);
+			new_id = realloc(s->port_in_id,
+					 (s->n_ports_in + 1) * sizeof(uint32_t));
+			new_type = realloc(s->port_in_type,
+					   (s->n_ports_in + 1) * sizeof(char *));
+			new_params = realloc(s->port_in_params,
+					     (s->n_ports_in + 1) * sizeof(void *));
+			if (!port_type || !new_id || !new_type || !new_params) {
+				uintptr_t pt = (uintptr_t)port_type;
+
+				port_in_params_free(p, tokens[3]);
+				free((void *)pt);
+				free(new_id);
+				free(new_type);
+				free(new_params);
+
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Memory allocation failed.";
+				goto error;
+			}
+
+			s->port_in_id = new_id;
+			s->port_in_type = new_type;
+			s->port_in_params = new_params;
+
+			s->port_in_id[s->n_ports_in] = port_id;
+			s->port_in_type[s->n_ports_in] = port_type;
+			s->port_in_params[s->n_ports_in] = p;
+			s->n_ports_in++;
+
+			continue;
+		}
+
+		/* port out. */
+		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "out")) {
+			char *token = tokens[2];
+			uint32_t *new_id = NULL;
+			const char **new_type = NULL, *port_type = NULL;
+			void **new_params = NULL, *p = NULL;
+			uint32_t port_id;
+
+			/* <port_id>. */
+			port_id = strtoul(token, &token, 0);
+			if (token[0]) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Invalid port ID.";
+				goto error;
+			}
+
+			/* <port_type>. */
+			if (!strcmp(tokens[3], "ethdev"))
+				p = port_out_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "ring"))
+				p = port_out_ring_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "sink"))
+				p = port_out_sink_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "fd"))
+				p = port_out_fd_parse(&tokens[4], n_tokens - 4, err_msg);
+			else {
+				p = NULL;
+				if (err_msg)
+					*err_msg = "Invalid port type.";
+			}
+
+			if (!p) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			/* New port. */
+			port_type = strdup(tokens[3]);
+			new_id = realloc(s->port_out_id,
+					 (s->n_ports_out + 1) * sizeof(uint32_t));
+			new_type = realloc(s->port_out_type,
+					   (s->n_ports_out + 1) * sizeof(char *));
+			new_params = realloc(s->port_out_params,
+					     (s->n_ports_out + 1) * sizeof(void *));
+			if (!port_type || !new_id || !new_type || !new_params) {
+				uintptr_t pt = (uintptr_t)port_type;
+
+				port_out_params_free(p, tokens[3]);
+				free((void *)pt);
+				free(new_id);
+				free(new_type);
+				free(new_params);
+
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Memory allocation failed.";
+				goto error;
+			}
+
+			s->port_out_id = new_id;
+			s->port_out_type = new_type;
+			s->port_out_params = new_params;
+
+			s->port_out_id[s->n_ports_out] = port_id;
+			s->port_out_type[s->n_ports_out] = port_type;
+			s->port_out_params[s->n_ports_out] = p;
+			s->n_ports_out++;
+
+			continue;
+		}
+
+		/* Anything else. */
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Unknown I/O statement.";
+		goto error;
+	}
+
+	return s;
+
+error:
+	pipeline_iospec_free(s);
+
+	return NULL;
+}
+
+int
+pipeline_iospec_configure(struct rte_swx_pipeline *p,
+			  struct pipeline_iospec *s,
+			  const char **err_msg)
+{
+	uint32_t i;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!p || !s) {
+		if (err_msg)
+			*err_msg = "Invalid input argument";
+		return -EINVAL;
+	}
+
+	/* Mirroring. */
+	status = rte_swx_pipeline_mirroring_config(p, &s->mirroring_params);
+	if (status) {
+		if (err_msg)
+			*err_msg = "Pipeline mirroring configuration error.";
+		return status;
+	}
+
+	/* Input ports. */
+	for (i = 0; i < s->n_ports_in; i++) {
+		status = rte_swx_pipeline_port_in_config(p,
+							 i,
+							 s->port_in_type[i],
+							 s->port_in_params[i]);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline input port configuration error.";
+			return status;
+		}
+	}
+
+	/* Output ports. */
+	for (i = 0; i < s->n_ports_out; i++) {
+		status = rte_swx_pipeline_port_out_config(p,
+							  i,
+							  s->port_out_type[i],
+							  s->port_out_params[i]);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline output port configuration error.";
+			return status;
+		}
+	}
+
+	return 0;
+}
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 707b99ba09..62ac4ecfc4 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -1,6 +1,13 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright(c) 2022 Intel Corporation
  */
+#ifndef __INCLUDE_RTE_SWX_PIPELINE_SPEC_H__
+#define __INCLUDE_RTE_SWX_PIPELINE_SPEC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <stdint.h>
 #include <stdio.h>
 
@@ -204,6 +211,38 @@ struct pipeline_spec {
 	uint32_t n_apply;
 };
 
+/*
+ * Mirroring:
+ *      mirroring slots <n_slots> sessions <n_sessions>
+ *
+ * Input ports:
+ *      port in <port_id> ethdev <ethdev_name> rxq <queue_id> bsz <burst_size>
+ *      port in <port_id> ring <ring_name> bsz <burst_size>
+ *      port in <port_id> source mempool <mempool_name> file <file_name> loop <n_loops>
+ *                               packets <n_pkts_max>
+ *      port in <port_id> fd <file_descriptor> mtu <mtu> mempool <mempool_name> bsz <burst_size>
+ *
+ * Output ports:
+ *      port out <port_id> ethdev <ethdev_name> txq <queue_id> bsz <burst_size>
+ *      port out <port_id> ring <ring_name> bsz <burst_size>
+ *      port out <port_id> sink file <file_name> | none
+ *      port out <port_id> fd <file_descriptor> bsz <burst_size>
+ */
+struct pipeline_iospec {
+	struct rte_swx_pipeline_mirroring_params mirroring_params;
+
+	uint32_t *port_in_id;
+	const char **port_in_type;
+	void **port_in_params;
+
+	uint32_t *port_out_id;
+	const char **port_out_type;
+	void **port_out_params;
+
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+};
+
 void
 pipeline_spec_free(struct pipeline_spec *s);
 
@@ -220,3 +259,22 @@ int
 pipeline_spec_configure(struct rte_swx_pipeline *p,
 			struct pipeline_spec *s,
 			const char **err_msg);
+
+void
+pipeline_iospec_free(struct pipeline_iospec *s);
+
+struct pipeline_iospec *
+pipeline_iospec_parse(FILE *spec,
+		      uint32_t *err_line,
+		      const char **err_msg);
+
+int
+pipeline_iospec_configure(struct rte_swx_pipeline *p,
+			  struct pipeline_iospec *s,
+			  const char **err_msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 07/17] pipeline: add API for pipeline code generation
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (4 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
                       ` (10 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the C code generation for the pipeline was hidden under
the hood; now, we make this an explicit API operation. Besides the
functions for the pipeline actions and the pipeline instructions,
the generated C source code now includes the pipeline specification
structure required for the pipeline configuration operations.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline.c | 94 +++++++++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline.h | 25 +++++++++
 lib/pipeline/version.map        |  1 +
 3 files changed, 120 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index c8ccded4f8..dd5f7107fa 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -20,6 +20,7 @@
 #include <rte_swx_table_wm.h>
 
 #include "rte_swx_pipeline_internal.h"
+#include "rte_swx_pipeline_spec.h"
 
 #define CHECK(condition, err_code)                                             \
 do {                                                                           \
@@ -13581,3 +13582,96 @@ pipeline_compile(struct rte_swx_pipeline *p)
 
 	return status;
 }
+
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg)
+
+{
+	struct rte_swx_pipeline *p = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!spec_file || !code_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	status = rte_swx_pipeline_config(&p, NULL, 0);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline configuration error.";
+		goto free;
+	}
+
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto free;
+	}
+
+	/*
+	 * Pipeline code generation.
+	 */
+
+	/* Instruction Group List (IGL) computation: the pipeline configuration must be done first,
+	 * but there is no need for the pipeline build to be done as well.
+	 */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
+		goto free;
+	}
+
+	/* Header file inclusion. */
+	fprintf(code_file, "#include \"rte_swx_pipeline_internal.h\"\n");
+	fprintf(code_file, "#include \"rte_swx_pipeline_spec.h\"\n\n");
+
+	/* Code generation for the pipeline specification. */
+	pipeline_spec_codegen(code_file, s);
+	fprintf(code_file, "\n");
+
+	/* Code generation for the action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		fprintf(code_file, "/**\n * Action %s\n */\n\n", a->name);
+
+		action_data_codegen(a, code_file);
+		fprintf(code_file, "\n");
+
+		action_instr_codegen(a, code_file);
+		fprintf(code_file, "\n");
+	}
+
+	/* Code generation for the pipeline instructions. */
+	instruction_group_list_codegen(igl, p, code_file);
+
+free:
+	instruction_group_list_free(igl);
+	rte_swx_pipeline_free(p);
+	pipeline_spec_free(s);
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index ef50a0fa70..724607b87c 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -957,6 +957,31 @@ __rte_experimental
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p);
 
+/**
+ * Pipeline C code generate based on input specification file
+ *
+ * @param[in] spec_file
+ *   Pipeline specification file (.spec) provided as input.
+ * @param[in] code_file
+ *   Pipeline C language file (.c) to be generated.
+ * @param[out] err_line
+ *   In case of error and non-NULL, the line number within the *spec* file where
+ *   the error occurred. The first line number in the file is 1.
+ * @param[out] err_msg
+ *   In case of error and non-NULL, the error message.
+ * @return
+ *   0 on success or the following error codes otherwise:
+ *   -EINVAL: Invalid argument;
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -EEXIST: Resource with the same name already exists.
+ */
+__rte_experimental
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg);
+
 /**
  * Pipeline build from specification file
  *
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 50029aadcf..8d95005a5b 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -148,5 +148,6 @@ EXPERIMENTAL {
 
 	#added in 22.11
 	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_codegen;
 	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 08/17] pipeline: add API for shared library-based pipeline build
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (5 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
                       ` (9 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the pipeline build operation was done based on the
specification file (typically produced by the P4 compiler), then the C
code with optimized functions for the pipeline actions and
instructions was generated, built into a shared object library, loaded
and installed into the pipeline in a completely hardcoded and
non-customizable way.

Now, this process is split into three explicit stages:
i) code generation (specification file -> C file);
ii) code build (C file -> shared object library);
iii) code installation (library load into the pipeline).

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c              |  85 ++++---
 lib/pipeline/rte_swx_pipeline.c      | 319 +++++++++++----------------
 lib/pipeline/rte_swx_pipeline.h      |  38 ++--
 lib/pipeline/rte_swx_pipeline_spec.c |  51 -----
 lib/pipeline/version.map             |   2 +-
 5 files changed, 208 insertions(+), 287 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index ad553f19ab..f0285675b3 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -984,55 +984,88 @@ cmd_pipeline_port_out(char **tokens,
 }
 
 static const char cmd_pipeline_build_help[] =
-"pipeline <pipeline_name> build <spec_file>\n";
+"pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
 static void
 cmd_pipeline_build(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p = NULL;
-	FILE *spec = NULL;
-	uint32_t err_line;
-	const char *err_msg;
-	int status;
+	struct rte_swx_pipeline *p = NULL;
+	struct rte_swx_ctl_pipeline *ctl = NULL;
+	char *pipeline_name, *lib_file_name, *iospec_file_name;
+	FILE *iospec_file = NULL;
+	uint32_t numa_node = 0;
+	int status = 0;
 
-	if (n_tokens != 4) {
+	/* Parsing. */
+	if (n_tokens != 9) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "build")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "build");
 		return;
 	}
 
-	spec = fopen(tokens[3], "r");
-	if (!spec) {
-		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
+	if (strcmp(tokens[3], "lib")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "lib");
 		return;
 	}
 
-	status = rte_swx_pipeline_build_from_spec(p->p,
-		spec,
-		&err_line,
-		&err_msg);
-	fclose(spec);
-	if (status) {
-		snprintf(out, out_size, "Error %d at line %u: %s\n.",
-			status, err_line, err_msg);
+	lib_file_name = tokens[4];
+
+	if (strcmp(tokens[5], "io")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "io");
 		return;
 	}
 
-	p->ctl = rte_swx_ctl_pipeline_create(p->p);
-	if (!p->ctl) {
-		snprintf(out, out_size, "Pipeline control create failed.");
-		rte_swx_pipeline_free(p->p);
+	iospec_file_name = tokens[6];
+
+	if (strcmp(tokens[7], "numa")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa");
 		return;
 	}
+
+	if (parser_read_uint32(&numa_node, tokens[8])) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "numa_node");
+		return;
+	}
+
+	/* I/O spec file open. */
+	iospec_file = fopen(iospec_file_name, "r");
+	if (!iospec_file) {
+		snprintf(out, out_size, "Cannot open file \"%s\".\n", iospec_file_name);
+		return;
+	}
+
+	status = rte_swx_pipeline_build_from_lib(&p,
+						 pipeline_name,
+						 lib_file_name,
+						 iospec_file,
+						 (int)numa_node);
+	if (status) {
+		snprintf(out, out_size, "Pipeline build failed (%d).", status);
+		goto free;
+	}
+
+	ctl = rte_swx_ctl_pipeline_create(p);
+	if (!ctl) {
+		snprintf(out, out_size, "Pipeline control create failed.");
+		goto free;
+	}
+
+free:
+	if (status)
+		rte_swx_pipeline_free(p);
+
+	if (iospec_file)
+		fclose(iospec_file);
 }
 
 static void
diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index dd5f7107fa..12e156b00b 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -9911,9 +9911,6 @@ rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p,
 	return 0;
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p);
-
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 {
@@ -10003,8 +10000,6 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 
 	p->build_done = 1;
 
-	pipeline_compile(p);
-
 	return 0;
 
 error:
@@ -13327,160 +13322,6 @@ instruction_group_list_custom_instructions_count(struct instruction_group_list *
 	return n_custom_instr;
 }
 
-static int
-pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	FILE *f = NULL;
-
-	/* Create the .c file. */
-	f = fopen("/tmp/pipeline.c", "w");
-	if (!f)
-		return -EIO;
-
-	/* Include the .h file. */
-	fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n");
-
-	/* Add the code for each action. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		fprintf(f, "/**\n * Action %s\n */\n\n", a->name);
-
-		action_data_codegen(a, f);
-
-		fprintf(f, "\n");
-
-		action_instr_codegen(a, f);
-
-		fprintf(f, "\n");
-	}
-
-	/* Add the pipeline code. */
-	instruction_group_list_codegen(igl, p, f);
-
-	/* Close the .c file. */
-	fclose(f);
-
-	return 0;
-}
-
-#ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE
-#define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096
-#endif
-
-static int
-pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	struct instruction_group *g;
-	char *dir_in, *buffer = NULL;
-	const char *dir_out;
-	int status = 0;
-
-	/* Get the environment variables. */
-	dir_in = getenv("RTE_INSTALL_DIR");
-	if (!dir_in) {
-		status = -EINVAL;
-		goto free;
-	}
-
-	dir_out = "/tmp";
-
-	/* Memory allocation for the command buffer. */
-	buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE);
-	if (!buffer) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c "
-		 "-I %s/lib/pipeline "
-		 "-I %s/lib/eal/include "
-		 "-I %s/lib/eal/x86/include "
-		 "-I %s/lib/eal/include/generic "
-		 "-I %s/lib/meter "
-		 "-I %s/lib/port "
-		 "-I %s/lib/table "
-		 "-I %s/lib/pipeline "
-		 "-I %s/config "
-		 "-I %s/build "
-		 "-I %s/lib/eal/linux/include "
-		 ">%s/pipeline.log 2>&1 "
-		 "&& "
-		 "gcc -shared %s/pipeline.o -o %s/libpipeline.so "
-		 ">>%s/pipeline.log 2>&1",
-		 dir_out,
-		 dir_out,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_out,
-		 dir_out,
-		 dir_out,
-		 dir_out);
-
-	/* Build the shared object library. */
-	status = system(buffer);
-	if (status)
-		goto free;
-
-	/* Open library. */
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "%s/libpipeline.so",
-		 dir_out);
-
-	p->lib = dlopen(buffer, RTLD_LAZY);
-	if (!p->lib) {
-		status = -EIO;
-		goto free;
-	}
-
-	/* Get the action function symbols. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name);
-
-		p->action_funcs[a->id] = dlsym(p->lib, buffer);
-		if (!p->action_funcs[a->id]) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-	/* Get the pipeline function symbols. */
-	TAILQ_FOREACH(g, igl, node) {
-		if (g->first_instr_id == g->last_instr_id)
-			continue;
-
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id);
-
-		g->func = dlsym(p->lib, buffer);
-		if (!g->func) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-free:
-	if (status && p->lib) {
-		dlclose(p->lib);
-		p->lib = NULL;
-	}
-
-	free(buffer);
-
-	return status;
-}
-
 static int
 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused,
 		      struct instruction_group_list *igl)
@@ -13548,41 +13389,6 @@ pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
 	instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions);
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p)
-{
-	struct instruction_group_list *igl = NULL;
-	int status = 0;
-
-	igl = instruction_group_list_create(p);
-	if (!igl) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	/* Code generation. */
-	status = pipeline_codegen(p, igl);
-	if (status)
-		goto free;
-
-	/* Build and load the shared object library. */
-	status = pipeline_libload(p, igl);
-	if (status)
-		goto free;
-
-	/* Adjust instructions. */
-	status = pipeline_adjust_check(p, igl);
-	if (status)
-		goto free;
-
-	pipeline_adjust(p, igl);
-
-free:
-	instruction_group_list_free(igl);
-
-	return status;
-}
-
 int
 rte_swx_pipeline_codegen(FILE *spec_file,
 			 FILE *code_file,
@@ -13675,3 +13481,128 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 
 	return status;
 }
+
+int
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline **pipeline,
+				const char *name,
+				const char *lib_file_name,
+				FILE *iospec_file,
+				int numa_node)
+{
+	struct rte_swx_pipeline *p = NULL;
+	void *lib = NULL;
+	struct pipeline_iospec *sio = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	struct instruction_group *g;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!pipeline ||
+	    !name ||
+	    !name[0] ||
+	    !lib_file_name ||
+	    !lib_file_name[0] ||
+	    !iospec_file) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Open the library. */
+	lib = dlopen(lib_file_name, RTLD_LAZY);
+	if (!lib) {
+		status = -EIO;
+		goto free;
+	}
+
+	/* Get the pipeline specification structures. */
+	s = dlsym(lib, "pipeline_spec");
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	sio = pipeline_iospec_parse(iospec_file, NULL, NULL);
+	if (!sio) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration based on the specification structures. */
+	status = rte_swx_pipeline_config(&p, name, numa_node);
+	if (status)
+		goto free;
+
+	status = pipeline_iospec_configure(p, sio, NULL);
+	if (status)
+		goto free;
+
+	status = pipeline_spec_configure(p, s, NULL);
+	if (status)
+		goto free;
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status)
+		goto free;
+
+	/* Action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		snprintf(name, sizeof(name), "action_%s_run", a->name);
+
+		p->action_funcs[a->id] = dlsym(lib, name);
+		if (!p->action_funcs[a->id]) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	/* Pipeline instructions. */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		status = -ENOMEM;
+		goto free;
+	}
+
+	TAILQ_FOREACH(g, igl, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		if (g->first_instr_id == g->last_instr_id)
+			continue;
+
+		snprintf(name, sizeof(name), "pipeline_func_%u", g->group_id);
+
+		g->func = dlsym(lib, name);
+		if (!g->func) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	status = pipeline_adjust_check(p, igl);
+	if (status)
+		goto free;
+
+	pipeline_adjust(p, igl);
+
+	p->lib = lib;
+
+	*pipeline = p;
+
+free:
+	instruction_group_list_free(igl);
+
+	pipeline_iospec_free(sio);
+
+	if (status) {
+		rte_swx_pipeline_free(p);
+
+		if (lib)
+			dlclose(lib);
+	}
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index 724607b87c..9c629d4118 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -983,30 +983,38 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 			 const char **err_msg);
 
 /**
- * Pipeline build from specification file
+ * Pipeline build from shared object library
  *
- * @param[in] p
- *   Pipeline handle.
- * @param[in] spec
- *   Pipeline specification file.
- * @param[out] err_line
- *   In case of error and non-NULL, the line number within the *spec* file where
- *   the error occurred. The first line number in the file is 1.
- * @param[out] err_msg
- *   In case of error and non-NULL, the error message.
+ * The shared object library must be built from the C language source code file
+ * previously generated by the rte_swx_pipeline_codegen() API function.
+ *
+ * The pipeline I/O specification file defines the I/O ports of the pipeline.
+ *
+ * @param[out] p
+ *   Pipeline handle. Must point to valid memory. Contains valid pipeline handle
+ *   when the function returns successfully.
+ * @param[in] name
+ *   Pipeline unique name.
+ * @param[in] lib_file_name
+ *   Shared object library file name.
+ * @param[in] iospec_file
+ *   Pipeline I/O specification file.
+ * @param[in] numa_node
+ *   Non-Uniform Memory Access (NUMA) node.
  * @return
  *   0 on success or the following error codes otherwise:
  *   -EINVAL: Invalid argument;
  *   -ENOMEM: Not enough space/cannot allocate memory;
- *   -EEXIST: Resource with the same name already exists;
+ *   -EEXIST: Pipeline with this name already exists;
  *   -ENODEV: Extern object or table creation error.
  */
 __rte_experimental
 int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg);
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline **p,
+				const char *name,
+				const char *lib_file_name,
+				FILE *iospec_file,
+				int numa_node);
 
 /**
  * Pipeline run
diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 89cf194b19..c0ca3dc131 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -3522,57 +3522,6 @@ pipeline_spec_configure(struct rte_swx_pipeline *p,
 	return 0;
 }
 
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec_file,
-				 uint32_t *err_line,
-				 const char **err_msg)
-{
-	struct pipeline_spec *s = NULL;
-	int status = 0;
-
-	/* Check the input arguments. */
-	if (!p || !spec_file) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Invalid input argument.";
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Spec file parse. */
-	s = pipeline_spec_parse(spec_file, err_line, err_msg);
-	if (!s) {
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Pipeline configure. */
-	status = pipeline_spec_configure(p, s, err_msg);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		goto error;
-	}
-
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
-
-error:
-	pipeline_spec_free(s);
-	return status;
-}
-
 static void
 port_in_params_free(void *params, const char *port_type)
 {
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 8d95005a5b..16806e6802 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -82,7 +82,6 @@ EXPERIMENTAL {
 	rte_swx_ctl_table_ops_get;
 	rte_swx_pipeline_action_config;
 	rte_swx_pipeline_build;
-	rte_swx_pipeline_build_from_spec;
 	rte_swx_pipeline_config;
 	rte_swx_pipeline_extern_func_register;
 	rte_swx_pipeline_extern_object_config;
@@ -148,6 +147,7 @@ EXPERIMENTAL {
 
 	#added in 22.11
 	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_build_from_lib;
 	rte_swx_pipeline_codegen;
 	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 09/17] examples/pipeline: add CLI command for pipeline code generation
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (6 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
                       ` (8 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the pipeline code generation operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 61 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index f0285675b3..2b38977be1 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -983,6 +983,53 @@ cmd_pipeline_port_out(char **tokens,
 	}
 }
 
+static const char cmd_pipeline_codegen_help[] =
+"pipeline codegen <spec_file> <code_file>\n";
+
+static void
+cmd_pipeline_codegen(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	FILE *spec_file = NULL;
+	FILE *code_file = NULL;
+	uint32_t err_line;
+	const char *err_msg;
+	int status;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	spec_file = fopen(tokens[2], "r");
+	if (!spec_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[2]);
+		return;
+	}
+
+	code_file = fopen(tokens[3], "w");
+	if (!code_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
+		return;
+	}
+
+	status = rte_swx_pipeline_codegen(spec_file,
+					  code_file,
+					  &err_line,
+					  &err_msg);
+
+	fclose(spec_file);
+	fclose(code_file);
+
+	if (status) {
+		snprintf(out, out_size, "Error %d at line %u: %s\n.",
+			status, err_line, err_msg);
+		return;
+	}
+}
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
@@ -3009,6 +3056,7 @@ cmd_help(char **tokens,
 			"\tpipeline create\n"
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
+			"\tpipeline codegen\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3078,6 +3126,12 @@ cmd_help(char **tokens,
 		}
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3356,6 +3410,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "codegen") == 0)) {
+			cmd_pipeline_codegen(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 10/17] examples/pipeline: add CLI command for shared library build
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (7 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
                       ` (7 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the shared object library build operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 157 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 153 insertions(+), 4 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 2b38977be1..28cf8d4178 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -6,6 +6,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_ethdev.h>
@@ -25,6 +26,10 @@
 #define CMD_MAX_TOKENS     256
 #endif
 
+#ifndef MAX_LINE_SIZE
+#define MAX_LINE_SIZE 2048
+#endif
+
 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
@@ -1030,6 +1035,140 @@ cmd_pipeline_codegen(char **tokens,
 		return;
 	}
 }
+
+static const char cmd_pipeline_libbuild_help[] =
+"pipeline libbuild <code_file> <lib_file>\n";
+
+static void
+cmd_pipeline_libbuild(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	char *code_file, *lib_file, *obj_file = NULL, *log_file = NULL;
+	char *install_dir, *cwd = NULL, *buffer = NULL;
+	size_t length;
+	int status = 0;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		goto free;
+	}
+
+	install_dir = getenv("RTE_INSTALL_DIR");
+	if (!install_dir) {
+		cwd = malloc(MAX_LINE_SIZE);
+		if (!cwd) {
+			snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+			goto free;
+		}
+
+		install_dir = getcwd(cwd, MAX_LINE_SIZE);
+		if (!install_dir) {
+			snprintf(out, out_size, "Error: Path too long.\n");
+			goto free;
+		}
+	}
+
+	snprintf(out, out_size, "Using DPDK source code from \"%s\".\n", install_dir);
+	out_size -= strlen(out);
+	out += strlen(out);
+
+	code_file = tokens[2];
+	length = strnlen(code_file, MAX_LINE_SIZE);
+	if ((length < 3) ||
+	    (code_file[length - 2] != '.') ||
+	    (code_file[length - 1] != 'c')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "code_file");
+		goto free;
+	}
+
+	lib_file = tokens[3];
+	length = strnlen(lib_file, MAX_LINE_SIZE);
+	if ((length < 4) ||
+	    (lib_file[length - 3] != '.') ||
+	    (lib_file[length - 2] != 's') ||
+	    (lib_file[length - 1] != 'o')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "lib_file");
+		goto free;
+	}
+
+	obj_file = malloc(length);
+	log_file = malloc(length + 2);
+	if (!obj_file || !log_file) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		goto free;
+	}
+
+	memcpy(obj_file, lib_file, length - 2);
+	obj_file[length - 2] = 'o';
+	obj_file[length - 1] = 0;
+
+	memcpy(log_file, lib_file, length - 2);
+	log_file[length - 2] = 'l';
+	log_file[length - 1] = 'o';
+	log_file[length] = 'g';
+	log_file[length + 1] = 0;
+
+	buffer = malloc(MAX_LINE_SIZE);
+	if (!buffer) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		return;
+	}
+
+	snprintf(buffer,
+		 MAX_LINE_SIZE,
+		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s %s "
+		 "-I %s/lib/pipeline "
+		 "-I %s/lib/eal/include "
+		 "-I %s/lib/eal/x86/include "
+		 "-I %s/lib/eal/include/generic "
+		 "-I %s/lib/meter "
+		 "-I %s/lib/port "
+		 "-I %s/lib/table "
+		 "-I %s/lib/pipeline "
+		 "-I %s/config "
+		 "-I %s/build "
+		 "-I %s/lib/eal/linux/include "
+		 ">%s 2>&1 "
+		 "&& "
+		 "gcc -shared %s -o %s "
+		 ">>%s 2>&1",
+		 obj_file,
+		 code_file,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 log_file,
+		 obj_file,
+		 lib_file,
+		 log_file);
+
+	status = system(buffer);
+	if (status) {
+		snprintf(out,
+			 out_size,
+			 "Library build failed, see file \"%s\" for details.\n",
+			 log_file);
+		goto free;
+	}
+
+free:
+	free(cwd);
+	free(obj_file);
+	free(log_file);
+	free(buffer);
+}
+
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
@@ -1127,10 +1266,6 @@ table_entry_free(struct rte_swx_table_entry *entry)
 	free(entry);
 }
 
-#ifndef MAX_LINE_SIZE
-#define MAX_LINE_SIZE 2048
-#endif
-
 static int
 pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p,
 			   const char *table_name,
@@ -3057,6 +3192,7 @@ cmd_help(char **tokens,
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
+			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3132,6 +3268,12 @@ cmd_help(char **tokens,
 		return;
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "libbuild") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_libbuild_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3417,6 +3559,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "libbuild") == 0)) {
+			cmd_pipeline_libbuild(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 11/17] examples/pipeline: remove the obsolete pipeline create CLI command
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (8 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
                       ` (6 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline configuration is now done through the I/O specification
file, hence this CLI command is no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 47 -----------------------------------------
 1 file changed, 47 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 28cf8d4178..7b725a9c27 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -523,39 +523,6 @@ cmd_tap(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_create_help[] =
-"pipeline <pipeline_name> create <numa_node>\n";
-
-static void
-cmd_pipeline_create(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	char *name;
-	uint32_t numa_node;
-
-	if (n_tokens != 4) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	name = tokens[1];
-
-	if (parser_read_uint32(&numa_node, tokens[3]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "numa_node");
-		return;
-	}
-
-	p = pipeline_create(obj, name, (int)numa_node);
-	if (!p) {
-		snprintf(out, out_size, "pipeline create error.");
-		return;
-	}
-}
-
 static const char cmd_pipeline_port_in_help[] =
 "pipeline <pipeline_name> port in <port_id>\n"
 "   link <link_name> rxq <queue_id> bsz <burst_size>\n"
@@ -3188,7 +3155,6 @@ cmd_help(char **tokens,
 			"\tmempool\n"
 			"\tlink\n"
 			"\ttap\n"
-			"\tpipeline create\n"
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
@@ -3241,12 +3207,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if ((strcmp(tokens[0], "pipeline") == 0) &&
-		(n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
-		snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
-		return;
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
 		if (strcmp(tokens[2], "in") == 0) {
@@ -3529,13 +3489,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 	}
 
 	if (strcmp(tokens[0], "pipeline") == 0) {
-		if ((n_tokens >= 3) &&
-			(strcmp(tokens[2], "create") == 0)) {
-			cmd_pipeline_create(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
 		if ((n_tokens >= 4) &&
 			(strcmp(tokens[2], "port") == 0) &&
 			(strcmp(tokens[3], "in") == 0)) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 12/17] examples/pipeline: remove the obsolete port configuration CLI commands
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (9 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
                       ` (5 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline I/O ports configuration is now done through the I/O
specification file, hence these CLI commands are no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 465 ----------------------------------------
 1 file changed, 465 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 7b725a9c27..b26e73c706 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -523,438 +523,6 @@ cmd_tap(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_port_in_help[] =
-"pipeline <pipeline_name> port in <port_id>\n"
-"   link <link_name> rxq <queue_id> bsz <burst_size>\n"
-"   ring <ring_name> bsz <burst_size>\n"
-"   | source <mempool_name> <file_name> loop <n_loops>\n"
-"   | tap <tap_name> mempool <mempool_name> mtu <mtu> bsz <burst_size>\n";
-
-static void
-cmd_pipeline_port_in(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	int status;
-	uint32_t port_id = 0, t0;
-
-	if (n_tokens < 6) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[2], "port") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
-		return;
-	}
-
-	if (strcmp(tokens[3], "in") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
-		return;
-	}
-
-	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-		return;
-	}
-
-	t0 = 5;
-
-	if (strcmp(tokens[t0], "link") == 0) {
-		struct rte_swx_port_ethdev_reader_params params;
-		struct link *link;
-
-		if (n_tokens < t0 + 6) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in link");
-			return;
-		}
-
-		link = link_find(obj, tokens[t0 + 1]);
-		if (!link) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"link_name");
-			return;
-		}
-		params.dev_name = link->dev_name;
-
-		if (strcmp(tokens[t0 + 2], "rxq") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
-			return;
-		}
-
-		if (parser_read_uint16(&params.queue_id, tokens[t0 + 3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"queue_id");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 4], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 5])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 6;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"ethdev",
-			&params);
-	} else if (strcmp(tokens[t0], "ring") == 0) {
-		struct rte_swx_port_ring_reader_params params;
-		struct ring *ring;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in ring");
-			return;
-		}
-
-		ring = ring_find(obj, tokens[t0 + 1]);
-		if (!ring) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"ring_name");
-			return;
-		}
-		params.name = ring->name;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"ring",
-			&params);
-	} else if (strcmp(tokens[t0], "source") == 0) {
-		struct rte_swx_port_source_params params;
-		struct mempool *mp;
-
-		if (n_tokens < t0 + 5) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in source");
-			return;
-		}
-
-		mp = mempool_find(obj, tokens[t0 + 1]);
-		if (!mp) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"mempool_name");
-			return;
-		}
-		params.pool = mp->m;
-
-		params.file_name = tokens[t0 + 2];
-
-		if (strcmp(tokens[t0 + 3], "loop") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "loop");
-			return;
-		}
-
-		if (parser_read_uint64(&params.n_loops, tokens[t0 + 4])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"n_loops");
-			return;
-		}
-
-		t0 += 5;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"source",
-			&params);
-	} else if (strcmp(tokens[t0], "tap") == 0) {
-		struct rte_swx_port_fd_reader_params params;
-		struct tap *tap;
-		struct mempool *mp;
-
-		if (n_tokens < t0 + 8) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in tap");
-			return;
-		}
-
-		tap = tap_find(obj, tokens[t0 + 1]);
-		if (!tap) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"tap_name");
-			return;
-		}
-		params.fd = tap->fd;
-
-		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
-				"mempool");
-			return;
-		}
-
-		mp = mempool_find(obj, tokens[t0 + 3]);
-		if (!mp) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"mempool_name");
-			return;
-		}
-		params.mempool = mp->m;
-
-		if (strcmp(tokens[t0 + 4], "mtu") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
-				"mtu");
-			return;
-		}
-
-		if (parser_read_uint32(&params.mtu, tokens[t0 + 5]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 6], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 7])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 8;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"fd",
-			&params);
-
-	} else {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (status) {
-		snprintf(out, out_size, "port in error.");
-		return;
-	}
-
-	if (n_tokens != t0) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-}
-
-static const char cmd_pipeline_port_out_help[] =
-"pipeline <pipeline_name> port out <port_id>\n"
-"   link <link_name> txq <txq_id> bsz <burst_size>\n"
-"   ring <ring_name> bsz <burst_size>\n"
-"   | sink <file_name> | none\n"
-"   | tap <tap_name> bsz <burst_size>\n";
-
-static void
-cmd_pipeline_port_out(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	int status;
-	uint32_t port_id = 0, t0;
-
-	if (n_tokens < 6) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[2], "port") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
-		return;
-	}
-
-	if (strcmp(tokens[3], "out") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
-		return;
-	}
-
-	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-		return;
-	}
-
-	t0 = 5;
-
-	if (strcmp(tokens[t0], "link") == 0) {
-		struct rte_swx_port_ethdev_writer_params params;
-		struct link *link;
-
-		if (n_tokens < t0 + 6) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out link");
-			return;
-		}
-
-		link = link_find(obj, tokens[t0 + 1]);
-		if (!link) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"link_name");
-			return;
-		}
-		params.dev_name = link->dev_name;
-
-		if (strcmp(tokens[t0 + 2], "txq") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
-			return;
-		}
-
-		if (parser_read_uint16(&params.queue_id, tokens[t0 + 3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"queue_id");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 4], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 5])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 6;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"ethdev",
-			&params);
-	} else if (strcmp(tokens[t0], "ring") == 0) {
-		struct rte_swx_port_ring_writer_params params;
-		struct ring *ring;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out link");
-			return;
-		}
-
-		ring = ring_find(obj, tokens[t0 + 1]);
-		if (!ring) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"ring_name");
-			return;
-		}
-		params.name = ring->name;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"ring",
-			&params);
-	} else if (strcmp(tokens[t0], "sink") == 0) {
-		struct rte_swx_port_sink_params params;
-
-		params.file_name = strcmp(tokens[t0 + 1], "none") ?
-			tokens[t0 + 1] : NULL;
-
-		t0 += 2;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"sink",
-			&params);
-	} else if (strcmp(tokens[t0], "tap") == 0) {
-		struct rte_swx_port_fd_writer_params params;
-		struct tap *tap;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out tap");
-			return;
-		}
-
-		tap = tap_find(obj, tokens[t0 + 1]);
-		if (!tap) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"tap_name");
-			return;
-		}
-		params.fd = tap->fd;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"fd",
-			&params);
-	} else {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (status) {
-		snprintf(out, out_size, "port out error.");
-		return;
-	}
-
-	if (n_tokens != t0) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-}
-
 static const char cmd_pipeline_codegen_help[] =
 "pipeline codegen <spec_file> <code_file>\n";
 
@@ -3155,8 +2723,6 @@ cmd_help(char **tokens,
 			"\tmempool\n"
 			"\tlink\n"
 			"\ttap\n"
-			"\tpipeline port in\n"
-			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
@@ -3207,21 +2773,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if ((strcmp(tokens[0], "pipeline") == 0) &&
-		(n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
-		if (strcmp(tokens[2], "in") == 0) {
-			snprintf(out, out_size, "\n%s\n",
-				cmd_pipeline_port_in_help);
-			return;
-		}
-
-		if (strcmp(tokens[2], "out") == 0) {
-			snprintf(out, out_size, "\n%s\n",
-				cmd_pipeline_port_out_help);
-			return;
-		}
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
@@ -3489,22 +3040,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 	}
 
 	if (strcmp(tokens[0], "pipeline") == 0) {
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "port") == 0) &&
-			(strcmp(tokens[3], "in") == 0)) {
-			cmd_pipeline_port_in(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "port") == 0) &&
-			(strcmp(tokens[3], "out") == 0)) {
-			cmd_pipeline_port_out(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[1], "codegen") == 0)) {
 			cmd_pipeline_codegen(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (10 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
                       ` (4 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline mirroring configuration is done through the I/O
specification file, so this CLI command is no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 76 -----------------------------------------
 1 file changed, 76 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index b26e73c706..fa828c008b 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -2457,68 +2457,6 @@ cmd_pipeline_stats(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_mirror_help[] =
-"pipeline <pipeline_name> mirror slots <n_slots> sessions <n_sessions>\n";
-
-static void
-cmd_pipeline_mirror(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct rte_swx_pipeline_mirroring_params params;
-	struct pipeline *p;
-	int status;
-
-	if (n_tokens != 7) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[0], "pipeline")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
-		return;
-	}
-
-	if (strcmp(tokens[2], "mirror")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror");
-		return;
-	}
-
-	if (strcmp(tokens[3], "slots")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "slots");
-		return;
-	}
-
-	if (parser_read_uint32(&params.n_slots, tokens[4])) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "n_slots");
-		return;
-	}
-
-	if (strcmp(tokens[5], "sessions")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "sessions");
-		return;
-	}
-
-	if (parser_read_uint32(&params.n_sessions, tokens[6])) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "n_sessions");
-		return;
-	}
-
-	status = rte_swx_pipeline_mirroring_config(p->p, &params);
-	if (status) {
-		snprintf(out, out_size, "Command failed!\n");
-		return;
-	}
-}
-
 static const char cmd_pipeline_mirror_session_help[] =
 "pipeline <pipeline_name> mirror session <session_id> port <port_id> clone fast | slow "
 "truncate <truncation_length>\n";
@@ -2746,7 +2684,6 @@ cmd_help(char **tokens,
 			"\tpipeline meter set\n"
 			"\tpipeline meter stats\n"
 			"\tpipeline stats\n"
-			"\tpipeline mirror\n"
 			"\tpipeline mirror session\n"
 			"\tthread pipeline enable\n"
 			"\tthread pipeline disable\n\n");
@@ -2958,12 +2895,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (!strcmp(tokens[0], "pipeline") &&
-		(n_tokens == 2) && !strcmp(tokens[1], "mirror")) {
-		snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_help);
-		return;
-	}
-
 	if (!strcmp(tokens[0], "pipeline") &&
 		(n_tokens == 3) && !strcmp(tokens[1], "mirror")
 		&& !strcmp(tokens[2], "session")) {
@@ -3217,13 +3148,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "mirror") == 0) &&
-			(strcmp(tokens[3], "slots") == 0)) {
-			cmd_pipeline_mirror(tokens, n_tokens, out, out_size, obj);
-			return;
-		}
-
 		if ((n_tokens >= 4) &&
 			(strcmp(tokens[2], "mirror") == 0) &&
 			(strcmp(tokens[3], "session") == 0)) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 14/17] examples/pipeline: use the pipeline name query API
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (11 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
                       ` (3 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Convert the CLI commands to use the pipeline name query API and remove
the linked list of pipeline objects previously maintained by the
application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c    | 268 ++++++++++++++++++++-----------------
 examples/pipeline/obj.c    |  67 ----------
 examples/pipeline/obj.h    |  24 ----
 examples/pipeline/thread.c |  65 ++++-----
 examples/pipeline/thread.h |   9 +-
 5 files changed, 175 insertions(+), 258 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index fa828c008b..f48ff326be 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -858,9 +858,9 @@ cmd_pipeline_table_add(char **tokens,
 		       uint32_t n_tokens,
 		       char *out,
 		       size_t out_size,
-		       void *obj)
+		       void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -872,8 +872,8 @@ cmd_pipeline_table_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -887,7 +887,7 @@ cmd_pipeline_table_add(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_entries_add(p->ctl,
+	status = pipeline_table_entries_add(ctl,
 					    table_name,
 					    file,
 					    &file_line_number);
@@ -956,9 +956,9 @@ cmd_pipeline_table_delete(char **tokens,
 			  uint32_t n_tokens,
 			  char *out,
 			  size_t out_size,
-			  void *obj)
+			  void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -970,8 +970,8 @@ cmd_pipeline_table_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -985,7 +985,7 @@ cmd_pipeline_table_delete(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_entries_delete(p->ctl,
+	status = pipeline_table_entries_delete(ctl,
 					       table_name,
 					       file,
 					       &file_line_number);
@@ -1054,9 +1054,9 @@ cmd_pipeline_table_default(char **tokens,
 			   uint32_t n_tokens,
 			   char *out,
 			   size_t out_size,
-			   void *obj)
+			   void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1068,8 +1068,8 @@ cmd_pipeline_table_default(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1083,7 +1083,7 @@ cmd_pipeline_table_default(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_default_entry_add(p->ctl,
+	status = pipeline_table_default_entry_add(ctl,
 						  table_name,
 						  file,
 						  &file_line_number);
@@ -1103,9 +1103,9 @@ cmd_pipeline_table_show(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name;
 	FILE *file = NULL;
 	int status;
@@ -1116,8 +1116,8 @@ cmd_pipeline_table_show(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1129,7 +1129,7 @@ cmd_pipeline_table_show(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_table_fprintf(file, p->ctl, table_name);
+	status = rte_swx_ctl_pipeline_table_fprintf(file, ctl, table_name);
 	if (status)
 		snprintf(out, out_size, MSG_ARG_INVALID, "table_name");
 
@@ -1145,9 +1145,9 @@ cmd_pipeline_selector_group_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	uint32_t group_id;
 	int status;
@@ -1158,8 +1158,8 @@ cmd_pipeline_selector_group_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1177,7 +1177,7 @@ cmd_pipeline_selector_group_add(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_group_add(p->ctl,
+	status = rte_swx_ctl_pipeline_selector_group_add(ctl,
 		selector_name,
 		&group_id);
 	if (status)
@@ -1194,9 +1194,9 @@ cmd_pipeline_selector_group_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	uint32_t group_id;
 	int status;
@@ -1207,8 +1207,8 @@ cmd_pipeline_selector_group_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1231,7 +1231,7 @@ cmd_pipeline_selector_group_delete(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_group_delete(p->ctl,
+	status = rte_swx_ctl_pipeline_selector_group_delete(ctl,
 		selector_name,
 		group_id);
 	if (status)
@@ -1402,9 +1402,9 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1416,8 +1416,8 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1443,7 +1443,7 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 		return;
 	}
 
-	status = pipeline_selector_group_members_add(p->ctl,
+	status = pipeline_selector_group_members_add(ctl,
 					    selector_name,
 					    file,
 					    &file_line_number);
@@ -1512,9 +1512,9 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1526,8 +1526,8 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1553,7 +1553,7 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 		return;
 	}
 
-	status = pipeline_selector_group_members_delete(p->ctl,
+	status = pipeline_selector_group_members_delete(ctl,
 					    selector_name,
 					    file,
 					    &file_line_number);
@@ -1573,9 +1573,9 @@ cmd_pipeline_selector_show(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	FILE *file = NULL;
 	int status;
@@ -1586,8 +1586,8 @@ cmd_pipeline_selector_show(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1600,7 +1600,7 @@ cmd_pipeline_selector_show(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_fprintf(file, p->ctl, selector_name);
+	status = rte_swx_ctl_pipeline_selector_fprintf(file, ctl, selector_name);
 	if (status)
 		snprintf(out, out_size, MSG_ARG_INVALID, "selector_name");
 
@@ -1665,9 +1665,9 @@ cmd_pipeline_learner_default(char **tokens,
 			     uint32_t n_tokens,
 			     char *out,
 			     size_t out_size,
-			     void *obj)
+			     void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *learner_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1679,8 +1679,8 @@ cmd_pipeline_learner_default(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1694,7 +1694,7 @@ cmd_pipeline_learner_default(char **tokens,
 		return;
 	}
 
-	status = pipeline_learner_default_entry_add(p->ctl,
+	status = pipeline_learner_default_entry_add(ctl,
 						    learner_name,
 						    file,
 						    &file_line_number);
@@ -1714,9 +1714,9 @@ cmd_pipeline_commit(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name;
 	int status;
 
@@ -1726,13 +1726,13 @@ cmd_pipeline_commit(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_commit(p->ctl, 1);
+	status = rte_swx_ctl_pipeline_commit(ctl, 1);
 	if (status)
 		snprintf(out, out_size, "Commit failed. "
 			"Use \"commit\" to retry or \"abort\" to discard the pending work.\n");
@@ -1746,9 +1746,9 @@ cmd_pipeline_abort(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name;
 
 	if (n_tokens != 3) {
@@ -1757,13 +1757,13 @@ cmd_pipeline_abort(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
 
-	rte_swx_ctl_pipeline_abort(p->ctl);
+	rte_swx_ctl_pipeline_abort(ctl);
 }
 
 static const char cmd_pipeline_regrd_help[] =
@@ -1774,9 +1774,9 @@ cmd_pipeline_regrd(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint64_t value;
 	uint32_t idx;
@@ -1787,8 +1787,8 @@ cmd_pipeline_regrd(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1805,7 +1805,7 @@ cmd_pipeline_regrd(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value);
+	status = rte_swx_ctl_pipeline_regarray_read(p, name, idx, &value);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1822,9 +1822,9 @@ cmd_pipeline_regwr(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint64_t value;
 	uint32_t idx;
@@ -1835,8 +1835,8 @@ cmd_pipeline_regwr(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1858,7 +1858,7 @@ cmd_pipeline_regwr(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value);
+	status = rte_swx_ctl_pipeline_regarray_write(p, name, idx, value);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1874,10 +1874,10 @@ cmd_pipeline_meter_profile_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_meter_trtcm_params params;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *profile_name;
 	int status;
 
@@ -1886,8 +1886,8 @@ cmd_pipeline_meter_profile_add(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1949,7 +1949,7 @@ cmd_pipeline_meter_profile_add(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_meter_profile_add(p->p, profile_name, &params);
+	status = rte_swx_ctl_meter_profile_add(p, profile_name, &params);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1964,9 +1964,9 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *profile_name;
 	int status;
 
@@ -1975,8 +1975,8 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1998,7 +1998,7 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_meter_profile_delete(p->p, profile_name);
+	status = rte_swx_ctl_meter_profile_delete(p, profile_name);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -2014,9 +2014,9 @@ cmd_pipeline_meter_reset(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2025,8 +2025,8 @@ cmd_pipeline_meter_reset(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2066,7 +2066,7 @@ cmd_pipeline_meter_reset(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_reset(p->p, name, idx0);
+		status = rte_swx_ctl_meter_reset(p, name, idx0);
 		if (status) {
 			snprintf(out, out_size, "Command failed for index %u.\n", idx0);
 			return;
@@ -2083,9 +2083,9 @@ cmd_pipeline_meter_set(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name, *profile_name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2094,8 +2094,8 @@ cmd_pipeline_meter_set(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2142,7 +2142,7 @@ cmd_pipeline_meter_set(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name);
+		status = rte_swx_ctl_meter_set(p, name, idx0, profile_name);
 		if (status) {
 			snprintf(out, out_size, "Command failed for index %u.\n", idx0);
 			return;
@@ -2159,10 +2159,10 @@ cmd_pipeline_meter_stats(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_ctl_meter_stats stats;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2171,8 +2171,8 @@ cmd_pipeline_meter_stats(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2235,7 +2235,7 @@ cmd_pipeline_meter_stats(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats);
+		status = rte_swx_ctl_meter_stats_read(p, name, idx0, &stats);
 		if (status) {
 			snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0);
 			out_size -= strlen(out);
@@ -2265,10 +2265,10 @@ cmd_pipeline_stats(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_ctl_pipeline_info info;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	uint32_t i;
 	int status;
 
@@ -2277,8 +2277,8 @@ cmd_pipeline_stats(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2288,7 +2288,7 @@ cmd_pipeline_stats(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_info_get(p->p, &info);
+	status = rte_swx_ctl_pipeline_info_get(p, &info);
 	if (status) {
 		snprintf(out, out_size, "Pipeline info get error.");
 		return;
@@ -2301,7 +2301,7 @@ cmd_pipeline_stats(char **tokens,
 	for (i = 0; i < info.n_ports_in; i++) {
 		struct rte_swx_port_in_stats stats;
 
-		rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats);
+		rte_swx_ctl_pipeline_port_in_stats_read(p, i, &stats);
 
 		snprintf(out, out_size, "\tPort %u:"
 			" packets %" PRIu64
@@ -2319,7 +2319,7 @@ cmd_pipeline_stats(char **tokens,
 	for (i = 0; i < info.n_ports_out; i++) {
 		struct rte_swx_port_out_stats stats;
 
-		rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats);
+		rte_swx_ctl_pipeline_port_out_stats_read(p, i, &stats);
 
 		if (i != info.n_ports_out - 1)
 			snprintf(out, out_size, "\tPort %u:", i);
@@ -2358,13 +2358,13 @@ cmd_pipeline_stats(char **tokens,
 		};
 		uint32_t j;
 
-		status = rte_swx_ctl_table_info_get(p->p, i, &table_info);
+		status = rte_swx_ctl_table_info_get(p, i, &table_info);
 		if (status) {
 			snprintf(out, out_size, "Table info get error.");
 			return;
 		}
 
-		status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats);
+		status = rte_swx_ctl_pipeline_table_stats_read(p, table_info.name, &stats);
 		if (status) {
 			snprintf(out, out_size, "Table stats read error.");
 			return;
@@ -2382,7 +2382,7 @@ cmd_pipeline_stats(char **tokens,
 		for (j = 0; j < info.n_actions; j++) {
 			struct rte_swx_ctl_action_info action_info;
 
-			status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
+			status = rte_swx_ctl_action_info_get(p, j, &action_info);
 			if (status) {
 				snprintf(out, out_size, "Action info get error.");
 				return;
@@ -2410,13 +2410,13 @@ cmd_pipeline_stats(char **tokens,
 		};
 		uint32_t j;
 
-		status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info);
+		status = rte_swx_ctl_learner_info_get(p, i, &learner_info);
 		if (status) {
 			snprintf(out, out_size, "Learner table info get error.");
 			return;
 		}
 
-		status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats);
+		status = rte_swx_ctl_pipeline_learner_stats_read(p, learner_info.name, &stats);
 		if (status) {
 			snprintf(out, out_size, "Learner table stats read error.");
 			return;
@@ -2442,7 +2442,7 @@ cmd_pipeline_stats(char **tokens,
 		for (j = 0; j < info.n_actions; j++) {
 			struct rte_swx_ctl_action_info action_info;
 
-			status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
+			status = rte_swx_ctl_action_info_get(p, j, &action_info);
 			if (status) {
 				snprintf(out, out_size, "Action info get error.");
 				return;
@@ -2466,10 +2466,10 @@ cmd_pipeline_mirror_session(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_pipeline_mirroring_session_params params;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	uint32_t session_id = 0;
 	int status;
 
@@ -2483,8 +2483,8 @@ cmd_pipeline_mirror_session(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2538,7 +2538,7 @@ cmd_pipeline_mirror_session(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_mirroring_session_set(p->p, session_id, &params);
+	status = rte_swx_ctl_pipeline_mirroring_session_set(p, session_id, &params);
 	if (status) {
 		snprintf(out, out_size, "Command failed!\n");
 		return;
@@ -2546,21 +2546,25 @@ cmd_pipeline_mirror_session(char **tokens,
 }
 
 static const char cmd_thread_pipeline_enable_help[] =
-"thread <thread_id> pipeline <pipeline_name> enable\n";
+"thread <thread_id> pipeline <pipeline_name> enable [ period <timer_period_ms> ]\n";
+
+#ifndef TIMER_PERIOD_MS_DEFAULT
+#define TIMER_PERIOD_MS_DEFAULT 10
+#endif
 
 static void
 cmd_thread_pipeline_enable(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	char *pipeline_name;
-	struct pipeline *p;
-	uint32_t thread_id;
+	struct rte_swx_pipeline *p;
+	uint32_t thread_id, timer_period_ms = TIMER_PERIOD_MS_DEFAULT;
 	int status;
 
-	if (n_tokens != 5) {
+	if ((n_tokens != 5) && (n_tokens != 7)) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
@@ -2576,8 +2580,8 @@ cmd_thread_pipeline_enable(char **tokens,
 	}
 
 	pipeline_name = tokens[3];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(pipeline_name);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2587,7 +2591,19 @@ cmd_thread_pipeline_enable(char **tokens,
 		return;
 	}
 
-	status = thread_pipeline_enable(thread_id, obj, pipeline_name);
+	if (n_tokens == 7) {
+		if (strcmp(tokens[5], "period") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
+			return;
+		}
+
+		if (parser_read_uint32(&timer_period_ms, tokens[6]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
+			return;
+		}
+	}
+
+	status = thread_pipeline_enable(thread_id, p, timer_period_ms);
 	if (status) {
 		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
 		return;
@@ -2602,9 +2618,9 @@ cmd_thread_pipeline_disable(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	char *pipeline_name;
 	uint32_t thread_id;
 	int status;
@@ -2625,8 +2641,8 @@ cmd_thread_pipeline_disable(char **tokens,
 	}
 
 	pipeline_name = tokens[3];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(pipeline_name);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2636,7 +2652,7 @@ cmd_thread_pipeline_disable(char **tokens,
 		return;
 	}
 
-	status = thread_pipeline_disable(thread_id, obj, pipeline_name);
+	status = thread_pipeline_disable(thread_id, p);
 	if (status) {
 		snprintf(out, out_size, MSG_CMD_FAIL,
 			"thread pipeline disable");
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index 967342c580..d1f519180e 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -16,7 +16,6 @@
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
-#include <rte_swx_pipeline.h>
 #include <rte_swx_ctl.h>
 
 #include "obj.h"
@@ -41,11 +40,6 @@ TAILQ_HEAD(ring_list, ring);
  */
 TAILQ_HEAD(tap_list, tap);
 
-/*
- * pipeline
- */
-TAILQ_HEAD(pipeline_list, pipeline);
-
 /*
  * obj
  */
@@ -53,7 +47,6 @@ struct obj {
 	struct mempool_list mempool_list;
 	struct link_list link_list;
 	struct ring_list ring_list;
-	struct pipeline_list pipeline_list;
 	struct tap_list tap_list;
 };
 
@@ -513,65 +506,6 @@ tap_create(struct obj *obj, const char *name)
 
 #endif
 
-/*
- * pipeline
- */
-#ifndef PIPELINE_MSGQ_SIZE
-#define PIPELINE_MSGQ_SIZE                                 64
-#endif
-
-struct pipeline *
-pipeline_create(struct obj *obj, const char *name, int numa_node)
-{
-	struct pipeline *pipeline;
-	struct rte_swx_pipeline *p = NULL;
-	int status;
-
-	/* Check input params */
-	if ((name == NULL) ||
-		pipeline_find(obj, name))
-		return NULL;
-
-	/* Resource create */
-	status = rte_swx_pipeline_config(&p, name, numa_node);
-	if (status)
-		goto error;
-
-	/* Node allocation */
-	pipeline = calloc(1, sizeof(struct pipeline));
-	if (pipeline == NULL)
-		goto error;
-
-	/* Node fill in */
-	strlcpy(pipeline->name, name, sizeof(pipeline->name));
-	pipeline->p = p;
-	pipeline->timer_period_ms = 10;
-
-	/* Node add to list */
-	TAILQ_INSERT_TAIL(&obj->pipeline_list, pipeline, node);
-
-	return pipeline;
-
-error:
-	rte_swx_pipeline_free(p);
-	return NULL;
-}
-
-struct pipeline *
-pipeline_find(struct obj *obj, const char *name)
-{
-	struct pipeline *pipeline;
-
-	if (!obj || !name)
-		return NULL;
-
-	TAILQ_FOREACH(pipeline, &obj->pipeline_list, node)
-		if (strcmp(name, pipeline->name) == 0)
-			return pipeline;
-
-	return NULL;
-}
-
 /*
  * obj
  */
@@ -587,7 +521,6 @@ obj_init(void)
 	TAILQ_INIT(&obj->mempool_list);
 	TAILQ_INIT(&obj->link_list);
 	TAILQ_INIT(&obj->ring_list);
-	TAILQ_INIT(&obj->pipeline_list);
 	TAILQ_INIT(&obj->tap_list);
 
 	return obj;
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index b921610554..e63a9c0e9a 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -143,28 +143,4 @@ tap_next(struct obj *obj, struct tap *tap);
 struct tap *
 tap_create(struct obj *obj, const char *name);
 
-/*
- * pipeline
- */
-struct pipeline {
-	TAILQ_ENTRY(pipeline) node;
-	char name[NAME_SIZE];
-
-	struct rte_swx_pipeline *p;
-	struct rte_swx_ctl_pipeline *ctl;
-
-	uint32_t timer_period_ms;
-	int enabled;
-	uint32_t thread_id;
-	uint32_t cpu_id;
-};
-
-struct pipeline *
-pipeline_create(struct obj *obj,
-		const char *name,
-		int numa_node);
-
-struct pipeline *
-pipeline_find(struct obj *obj, const char *name);
-
 #endif /* _INCLUDE_OBJ_H_ */
diff --git a/examples/pipeline/thread.c b/examples/pipeline/thread.c
index 5fe7eae00e..6d15f51fb2 100644
--- a/examples/pipeline/thread.c
+++ b/examples/pipeline/thread.c
@@ -228,20 +228,33 @@ thread_msg_send_recv(uint32_t thread_id,
 	return rsp;
 }
 
+static int
+thread_is_pipeline_enabled(uint32_t thread_id, struct rte_swx_pipeline *p)
+{
+	struct thread *t = &thread[thread_id];
+	struct thread_data *td = &thread_data[thread_id];
+	uint32_t i;
+
+	if (!t->enabled)
+		return 0; /* Pipeline NOT enabled on this thread. */
+
+	for (i = 0; i < td->n_pipelines; i++)
+		if (td->p[i] == p)
+			return 1; /* Pipeline enabled on this thread. */
+
+	return 0 /* Pipeline NOT enabled on this thread. */;
+}
+
 int
-thread_pipeline_enable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name)
+thread_pipeline_enable(uint32_t thread_id, struct rte_swx_pipeline *p, uint32_t timer_period_ms)
 {
-	struct pipeline *p = pipeline_find(obj, pipeline_name);
 	struct thread *t;
 	struct thread_msg_req *req;
 	struct thread_msg_rsp *rsp;
 	int status;
 
 	/* Check input params */
-	if ((thread_id >= RTE_MAX_LCORE) ||
-		(p == NULL))
+	if ((thread_id >= RTE_MAX_LCORE) || !p || !timer_period_ms)
 		return -1;
 
 	t = &thread[thread_id];
@@ -256,19 +269,14 @@ thread_pipeline_enable(uint32_t thread_id,
 			return -1;
 
 		/* Data plane thread */
-		td->p[td->n_pipelines] = p->p;
+		td->p[td->n_pipelines] = p;
 
-		tdp->p = p->p;
-		tdp->timer_period =
-			(rte_get_tsc_hz() * p->timer_period_ms) / 1000;
+		tdp->p = p;
+		tdp->timer_period = (rte_get_tsc_hz() * timer_period_ms) / 1000;
 		tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
 
 		td->n_pipelines++;
 
-		/* Pipeline */
-		p->thread_id = thread_id;
-		p->enabled = 1;
-
 		return 0;
 	}
 
@@ -279,8 +287,8 @@ thread_pipeline_enable(uint32_t thread_id,
 
 	/* Write request */
 	req->type = THREAD_REQ_PIPELINE_ENABLE;
-	req->pipeline_enable.p = p->p;
-	req->pipeline_enable.timer_period_ms = p->timer_period_ms;
+	req->pipeline_enable.p = p;
+	req->pipeline_enable.timer_period_ms = timer_period_ms;
 
 	/* Send request and wait for response */
 	rsp = thread_msg_send_recv(thread_id, req);
@@ -295,38 +303,28 @@ thread_pipeline_enable(uint32_t thread_id,
 	if (status)
 		return status;
 
-	p->thread_id = thread_id;
-	p->enabled = 1;
-
 	return 0;
 }
 
 int
-thread_pipeline_disable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name)
+thread_pipeline_disable(uint32_t thread_id, struct rte_swx_pipeline *p)
 {
-	struct pipeline *p = pipeline_find(obj, pipeline_name);
 	struct thread *t;
 	struct thread_msg_req *req;
 	struct thread_msg_rsp *rsp;
 	int status;
 
 	/* Check input params */
-	if ((thread_id >= RTE_MAX_LCORE) ||
-		(p == NULL))
+	if ((thread_id >= RTE_MAX_LCORE) || !p)
 		return -1;
 
 	t = &thread[thread_id];
 	if (t->enabled == 0)
 		return -1;
 
-	if (p->enabled == 0)
+	if (!thread_is_pipeline_enabled(thread_id, p))
 		return 0;
 
-	if (p->thread_id != thread_id)
-		return -1;
-
 	if (!thread_is_running(thread_id)) {
 		struct thread_data *td = &thread_data[thread_id];
 		uint32_t i;
@@ -334,7 +332,7 @@ thread_pipeline_disable(uint32_t thread_id,
 		for (i = 0; i < td->n_pipelines; i++) {
 			struct pipeline_data *tdp = &td->pipeline_data[i];
 
-			if (tdp->p != p->p)
+			if (tdp->p != p)
 				continue;
 
 			/* Data plane thread */
@@ -350,9 +348,6 @@ thread_pipeline_disable(uint32_t thread_id,
 
 			td->n_pipelines--;
 
-			/* Pipeline */
-			p->enabled = 0;
-
 			break;
 		}
 
@@ -366,7 +361,7 @@ thread_pipeline_disable(uint32_t thread_id,
 
 	/* Write request */
 	req->type = THREAD_REQ_PIPELINE_DISABLE;
-	req->pipeline_disable.p = p->p;
+	req->pipeline_disable.p = p;
 
 	/* Send request and wait for response */
 	rsp = thread_msg_send_recv(thread_id, req);
@@ -381,8 +376,6 @@ thread_pipeline_disable(uint32_t thread_id,
 	if (status)
 		return status;
 
-	p->enabled = 0;
-
 	return 0;
 }
 
diff --git a/examples/pipeline/thread.h b/examples/pipeline/thread.h
index d9d8645d4c..712cb25bbb 100644
--- a/examples/pipeline/thread.h
+++ b/examples/pipeline/thread.h
@@ -7,17 +7,16 @@
 
 #include <stdint.h>
 
-#include "obj.h"
+#include <rte_swx_pipeline.h>
 
 int
 thread_pipeline_enable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name);
+		       struct rte_swx_pipeline *p,
+		       uint32_t timer_period_ms);
 
 int
 thread_pipeline_disable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name);
+			struct rte_swx_pipeline *p);
 
 int
 thread_init(void);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 15/17] examples/pipeline: rework the link CLI command
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (12 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
                       ` (2 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Rework the link CLI command for better alignment with the naming
conventions used in the pipeline I/O specification file. Use the
library linked list of devices and remove the application list.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 81 +++++++++++++----------------------------
 examples/pipeline/obj.c | 16 ++------
 examples/pipeline/obj.h |  4 --
 3 files changed, 29 insertions(+), 72 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index f48ff326be..d56a830fb7 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -106,22 +106,6 @@ parser_read_uint32(uint32_t *value, const char *p)
 	return 0;
 }
 
-static int
-parser_read_uint16(uint16_t *value, const char *p)
-{
-	uint64_t val = 0;
-	int ret = parser_read_uint64(&val, p);
-
-	if (ret < 0)
-		return ret;
-
-	if (val > UINT16_MAX)
-		return -ERANGE;
-
-	*value = val;
-	return 0;
-}
-
 #define PARSE_DELIMITER " \f\n\r\t\v"
 
 static int
@@ -230,16 +214,15 @@ cmd_mempool(char **tokens,
 	}
 }
 
-static const char cmd_link_help[] =
-"link <link_name>\n"
-"   dev <device_name> | port <port_id>\n"
+static const char cmd_ethdev_help[] =
+"ethdev <ethdev_name>\n"
 "   rxq <n_queues> <queue_size> <mempool_name>\n"
 "   txq <n_queues> <queue_size>\n"
 "   promiscuous on | off\n"
 "   [rss <qid_0> ... <qid_n>]\n";
 
 static void
-cmd_link(char **tokens,
+cmd_ethdev(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
@@ -252,65 +235,51 @@ cmd_link(char **tokens,
 
 	memset(&p, 0, sizeof(p));
 
-	if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
+	if ((n_tokens < 11) || (n_tokens > 12 + LINK_RXQ_RSS_MAX)) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
 	name = tokens[1];
 
-	if (strcmp(tokens[2], "dev") == 0)
-		p.dev_name = tokens[3];
-	else if (strcmp(tokens[2], "port") == 0) {
-		p.dev_name = NULL;
-
-		if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-			return;
-		}
-	} else {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
-		return;
-	}
-
-	if (strcmp(tokens[4], "rxq") != 0) {
+	if (strcmp(tokens[2], "rxq") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
 		return;
 	}
 
-	if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
+	if (parser_read_uint32(&p.rx.n_queues, tokens[3]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
 		return;
 	}
-	if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
+	if (parser_read_uint32(&p.rx.queue_size, tokens[4]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
 		return;
 	}
 
-	p.rx.mempool_name = tokens[7];
+	p.rx.mempool_name = tokens[5];
 
-	if (strcmp(tokens[8], "txq") != 0) {
+	if (strcmp(tokens[6], "txq") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
 		return;
 	}
 
-	if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
+	if (parser_read_uint32(&p.tx.n_queues, tokens[7]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
 		return;
 	}
 
-	if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
+	if (parser_read_uint32(&p.tx.queue_size, tokens[8]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
 		return;
 	}
 
-	if (strcmp(tokens[11], "promiscuous") != 0) {
+	if (strcmp(tokens[9], "promiscuous") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
 		return;
 	}
 
-	if (strcmp(tokens[12], "on") == 0)
+	if (strcmp(tokens[10], "on") == 0)
 		p.promiscuous = 1;
-	else if (strcmp(tokens[12], "off") == 0)
+	else if (strcmp(tokens[10], "off") == 0)
 		p.promiscuous = 0;
 	else {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
@@ -319,10 +288,10 @@ cmd_link(char **tokens,
 
 	/* RSS */
 	p.rx.rss = NULL;
-	if (n_tokens > 13) {
+	if (n_tokens > 11) {
 		uint32_t queue_id, i;
 
-		if (strcmp(tokens[13], "rss") != 0) {
+		if (strcmp(tokens[11], "rss") != 0) {
 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
 			return;
 		}
@@ -330,7 +299,7 @@ cmd_link(char **tokens,
 		p.rx.rss = &rss;
 
 		rss.n_queues = 0;
-		for (i = 14; i < n_tokens; i++) {
+		for (i = 12; i < n_tokens; i++) {
 			if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
 				snprintf(out, out_size, MSG_ARG_INVALID,
 					"queue_id");
@@ -406,10 +375,10 @@ print_link_info(struct link *link, char *out, size_t out_size)
 }
 
 /*
- * link show [<link_name>]
+ * ethdev show [<ethdev_name>]
  */
 static void
-cmd_link_show(char **tokens,
+cmd_ethdev_show(char **tokens,
 	      uint32_t n_tokens,
 	      char *out,
 	      size_t out_size,
@@ -2675,7 +2644,7 @@ cmd_help(char **tokens,
 			"Type 'help <command>' for command details.\n\n"
 			"List of commands:\n"
 			"\tmempool\n"
-			"\tlink\n"
+			"\tethdev\n"
 			"\ttap\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
@@ -2711,8 +2680,8 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (strcmp(tokens[0], "link") == 0) {
-		snprintf(out, out_size, "\n%s\n", cmd_link_help);
+	if (strcmp(tokens[0], "ethdev") == 0) {
+		snprintf(out, out_size, "\n%s\n", cmd_ethdev_help);
 		return;
 	}
 
@@ -2966,13 +2935,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 		return;
 	}
 
-	if (strcmp(tokens[0], "link") == 0) {
+	if (strcmp(tokens[0], "ethdev") == 0) {
 		if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) {
-			cmd_link_show(tokens, n_tokens, out, out_size, obj);
+			cmd_ethdev_show(tokens, n_tokens, out, out_size, obj);
 			return;
 		}
 
-		cmd_link(tokens, n_tokens, out, out_size, obj);
+		cmd_ethdev(tokens, n_tokens, out, out_size, obj);
 		return;
 	}
 
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index d1f519180e..950ab831fb 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -181,7 +181,7 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 	struct mempool *mempool;
 	uint32_t cpu_id, i;
 	int status;
-	uint16_t port_id;
+	uint16_t port_id = 0;
 
 	/* Check input params */
 	if ((name == NULL) ||
@@ -193,16 +193,9 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 		(params->tx.queue_size == 0))
 		return NULL;
 
-	port_id = params->port_id;
-	if (params->dev_name) {
-		status = rte_eth_dev_get_port_by_name(params->dev_name,
-			&port_id);
-
-		if (status)
-			return NULL;
-	} else
-		if (!rte_eth_dev_is_valid_port(port_id))
-			return NULL;
+	status = rte_eth_dev_get_port_by_name(name, &port_id);
+	if (status)
+		return NULL;
 
 	if (rte_eth_dev_info_get(port_id, &port_info) != 0)
 		return NULL;
@@ -315,7 +308,6 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 	/* Node fill in */
 	strlcpy(link->name, name, sizeof(link->name));
 	link->port_id = port_id;
-	rte_eth_dev_get_name_by_port(port_id, link->dev_name);
 	link->n_rxq = params->rx.n_queues;
 	link->n_txq = params->tx.n_queues;
 
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index e63a9c0e9a..af270a8e57 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -63,9 +63,6 @@ struct link_params_rss {
 };
 
 struct link_params {
-	const char *dev_name;
-	uint16_t port_id; /**< Valid only when *dev_name* is NULL. */
-
 	struct {
 		uint32_t n_queues;
 		uint32_t queue_size;
@@ -84,7 +81,6 @@ struct link_params {
 struct link {
 	TAILQ_ENTRY(link) node;
 	char name[NAME_SIZE];
-	char dev_name[NAME_SIZE];
 	uint16_t port_id;
 	uint32_t n_rxq;
 	uint32_t n_txq;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 16/17] examples/pipelines: remove obsolete tap CLI command
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (13 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:36     ` [PATCH V3 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Remove the tap CLI command, as the file descriptor I/O ports of the
pipeline are now configured trough the I/O specification file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 37 -----------------
 examples/pipeline/obj.c | 89 -----------------------------------------
 examples/pipeline/obj.h | 18 ---------
 3 files changed, 144 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index d56a830fb7..75c32b9089 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -466,32 +466,6 @@ cmd_ring(char **tokens,
 	}
 }
 
-static const char cmd_tap_help[] =
-"tap <tap_name>\n";
-
-static void
-cmd_tap(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct tap *tap;
-	char *name;
-
-	if (n_tokens < 2) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-	name = tokens[1];
-
-	tap = tap_create(obj, name);
-	if (tap == NULL) {
-		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
-		return;
-	}
-}
-
 static const char cmd_pipeline_codegen_help[] =
 "pipeline codegen <spec_file> <code_file>\n";
 
@@ -2645,7 +2619,6 @@ cmd_help(char **tokens,
 			"List of commands:\n"
 			"\tmempool\n"
 			"\tethdev\n"
-			"\ttap\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
@@ -2690,11 +2663,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (strcmp(tokens[0], "tap") == 0) {
-		snprintf(out, out_size, "\n%s\n", cmd_tap_help);
-		return;
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
@@ -2950,11 +2918,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 		return;
 	}
 
-	if (strcmp(tokens[0], "tap") == 0) {
-		cmd_tap(tokens, n_tokens, out, out_size, obj);
-		return;
-	}
-
 	if (strcmp(tokens[0], "pipeline") == 0) {
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[1], "codegen") == 0)) {
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index 950ab831fb..b7e2316eec 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -35,11 +35,6 @@ TAILQ_HEAD(link_list, link);
  */
 TAILQ_HEAD(ring_list, ring);
 
-/*
- * tap
- */
-TAILQ_HEAD(tap_list, tap);
-
 /*
  * obj
  */
@@ -47,7 +42,6 @@ struct obj {
 	struct mempool_list mempool_list;
 	struct link_list link_list;
 	struct ring_list ring_list;
-	struct tap_list tap_list;
 };
 
 /*
@@ -416,88 +410,6 @@ ring_find(struct obj *obj, const char *name)
 	return NULL;
 }
 
-/*
- * tap
- */
-#define TAP_DEV		"/dev/net/tun"
-
-struct tap *
-tap_find(struct obj *obj, const char *name)
-{
-	struct tap *tap;
-
-	if (!obj || !name)
-		return NULL;
-
-	TAILQ_FOREACH(tap, &obj->tap_list, node)
-		if (strcmp(tap->name, name) == 0)
-			return tap;
-
-	return NULL;
-}
-
-struct tap *
-tap_next(struct obj *obj, struct tap *tap)
-{
-	return (tap == NULL) ?
-		TAILQ_FIRST(&obj->tap_list) : TAILQ_NEXT(tap, node);
-}
-
-#ifndef RTE_EXEC_ENV_LINUX
-
-struct tap *
-tap_create(struct obj *obj __rte_unused, const char *name __rte_unused)
-{
-	return NULL;
-}
-
-#else
-
-struct tap *
-tap_create(struct obj *obj, const char *name)
-{
-	struct tap *tap;
-	struct ifreq ifr;
-	int fd, status;
-
-	/* Check input params */
-	if ((name == NULL) ||
-		tap_find(obj, name))
-		return NULL;
-
-	/* Resource create */
-	fd = open(TAP_DEV, O_RDWR | O_NONBLOCK);
-	if (fd < 0)
-		return NULL;
-
-	memset(&ifr, 0, sizeof(ifr));
-	ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
-	strlcpy(ifr.ifr_name, name, IFNAMSIZ);
-
-	status = ioctl(fd, TUNSETIFF, (void *) &ifr);
-	if (status < 0) {
-		close(fd);
-		return NULL;
-	}
-
-	/* Node allocation */
-	tap = calloc(1, sizeof(struct tap));
-	if (tap == NULL) {
-		close(fd);
-		return NULL;
-	}
-	/* Node fill in */
-	strlcpy(tap->name, name, sizeof(tap->name));
-	tap->fd = fd;
-
-	/* Node add to list */
-	TAILQ_INSERT_TAIL(&obj->tap_list, tap, node);
-
-	return tap;
-}
-
-#endif
-
 /*
  * obj
  */
@@ -513,7 +425,6 @@ obj_init(void)
 	TAILQ_INIT(&obj->mempool_list);
 	TAILQ_INIT(&obj->link_list);
 	TAILQ_INIT(&obj->ring_list);
-	TAILQ_INIT(&obj->tap_list);
 
 	return obj;
 }
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index af270a8e57..8ea1c414c2 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -121,22 +121,4 @@ ring_create(struct obj *obj,
 struct ring *
 ring_find(struct obj *obj, const char *name);
 
-/*
- * tap
- */
-struct tap {
-	TAILQ_ENTRY(tap) node;
-	char name[NAME_SIZE];
-	int fd;
-};
-
-struct tap *
-tap_find(struct obj *obj, const char *name);
-
-struct tap *
-tap_next(struct obj *obj, struct tap *tap);
-
-struct tap *
-tap_create(struct obj *obj, const char *name);
-
 #endif /* _INCLUDE_OBJ_H_ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V3 17/17] examples/pipeline: call the code generation and build CLI commands
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (14 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
@ 2022-07-27 22:36     ` Cristian Dumitrescu
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:36 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Update the example CLI scripts with the commands for code generation
and shared object library build.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/examples/ethdev.io          | 27 +++++++++
 examples/pipeline/examples/fib.cli            | 44 +++++++-------
 examples/pipeline/examples/hash_func.cli      | 41 ++++++-------
 examples/pipeline/examples/l2fwd.cli          | 44 ++++++++------
 examples/pipeline/examples/l2fwd_macswp.cli   | 44 ++++++++------
 .../pipeline/examples/l2fwd_macswp_pcap.cli   | 35 +++++++----
 examples/pipeline/examples/l2fwd_pcap.cli     | 35 +++++++----
 examples/pipeline/examples/learner.cli        | 43 +++++++-------
 examples/pipeline/examples/meter.cli          | 58 +++++++++++--------
 examples/pipeline/examples/mirroring.cli      | 46 ++++++++-------
 examples/pipeline/examples/pcap.io            | 27 +++++++++
 examples/pipeline/examples/recirculation.cli  | 41 ++++++-------
 examples/pipeline/examples/registers.cli      | 53 +++++++++--------
 examples/pipeline/examples/selector.cli       | 55 +++++++++++-------
 examples/pipeline/examples/varbit.cli         | 41 ++++++-------
 examples/pipeline/examples/vxlan.cli          | 48 ++++++++++-----
 examples/pipeline/examples/vxlan_pcap.cli     | 39 +++++++++----
 17 files changed, 444 insertions(+), 277 deletions(-)
 create mode 100644 examples/pipeline/examples/ethdev.io
 create mode 100644 examples/pipeline/examples/pcap.io

diff --git a/examples/pipeline/examples/ethdev.io b/examples/pipeline/examples/ethdev.io
new file mode 100644
index 0000000000..cf2f3e20bd
--- /dev/null
+++ b/examples/pipeline/examples/ethdev.io
@@ -0,0 +1,27 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2022 Intel Corporation
+
+;
+; Pipeline packet mirroring.
+;
+mirroring slots 4 sessions 64
+
+;
+; Pipeline input ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port in 0 ethdev 0000:18:00.0 rxq 0 bsz 32
+port in 1 ethdev 0000:18:00.1 rxq 0 bsz 32
+port in 2 ethdev 0000:3b:00.0 rxq 0 bsz 32
+port in 3 ethdev 0000:3b:00.1 rxq 0 bsz 32
+
+;
+; Pipeline output ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port out 0 ethdev 0000:18:00.0 txq 0 bsz 32
+port out 1 ethdev 0000:18:00.1 txq 0 bsz 32
+port out 2 ethdev 0000:3b:00.0 txq 0 bsz 32
+port out 3 ethdev 0000:3b:00.1 txq 0 bsz 32
diff --git a/examples/pipeline/examples/fib.cli b/examples/pipeline/examples/fib.cli
index 93ab2b08f8..4e30c1320f 100644
--- a/examples/pipeline/examples/fib.cli
+++ b/examples/pipeline/examples/fib.cli
@@ -1,38 +1,38 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/fib.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/fib.spec /tmp/fib.c
+pipeline libbuild /tmp/fib.c /tmp/fib.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/fib.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/fib.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Initial set of table entries.
 ;
-; The table entries can later be updated at run-time through the CLI commands. Once the application
-; has been successfully started, the command to get the CLI prompt is: telnet 0.0.0.0 8086.
+; The table entries can later be updated at run-time through the CLI commands.
 ;
 pipeline PIPELINE0 table routing_table add ./examples/pipeline/examples/fib_routing_table.txt
 pipeline PIPELINE0 selector nexthop_group_table group add
diff --git a/examples/pipeline/examples/hash_func.cli b/examples/pipeline/examples/hash_func.cli
index d65cd62d17..b2e219e4c9 100644
--- a/examples/pipeline/examples/hash_func.cli
+++ b/examples/pipeline/examples/hash_func.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/hash_func.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/hash_func.spec /tmp/hash_func.c
+pipeline libbuild /tmp/hash_func.c /tmp/hash_func.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/hash_func.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/hash_func.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/l2fwd.cli b/examples/pipeline/examples/l2fwd.cli
index d89caf2d0a..27e37021b9 100644
--- a/examples/pipeline/examples/l2fwd.cli
+++ b/examples/pipeline/examples/l2fwd.cli
@@ -1,25 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd.so io ./examples/pipeline/examples/ethdev.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp.cli b/examples/pipeline/examples/l2fwd_macswp.cli
index 0f2a89ac5b..11bb4543b9 100644
--- a/examples/pipeline/examples/l2fwd_macswp.cli
+++ b/examples/pipeline/examples/l2fwd_macswp.cli
@@ -1,25 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_macswp.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd_macswp.so io ./examples/pipeline/examples/ethdev.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp_pcap.cli b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
index e9656fe3c2..8724dae3b0 100644
--- a/examples/pipeline/examples/l2fwd_macswp_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
@@ -1,20 +1,31 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-pipeline PIPELINE0 create 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_macswp_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd_macswp.so io ./examples/pipeline/examples/pcap.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_pcap.cli b/examples/pipeline/examples/l2fwd_pcap.cli
index 23fcb199f1..4db0a0dc56 100644
--- a/examples/pipeline/examples/l2fwd_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_pcap.cli
@@ -1,20 +1,31 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-pipeline PIPELINE0 create 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd.so io ./examples/pipeline/examples/pcap.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/learner.cli b/examples/pipeline/examples/learner.cli
index 688ce34f34..6c8aa3921e 100644
--- a/examples/pipeline/examples/learner.cli
+++ b/examples/pipeline/examples/learner.cli
@@ -1,36 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/learner.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/learner.spec /tmp/learner.c
+pipeline libbuild /tmp/learner.c /tmp/learner.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/learner.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/learner.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
 ;
 thread 1 pipeline PIPELINE0 enable
-
-; Once the application has started, the command to get the CLI prompt is: telnet 0.0.0.0 8086
diff --git a/examples/pipeline/examples/meter.cli b/examples/pipeline/examples/meter.cli
index b29ed24022..c1b88c882a 100644
--- a/examples/pipeline/examples/meter.cli
+++ b/examples/pipeline/examples/meter.cli
@@ -1,31 +1,43 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-; Example command line:
-;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/meter.cli
-
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/meter.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/meter.spec /tmp/meter.c
+pipeline libbuild /tmp/meter.c /tmp/meter.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/meter.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/meter.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 meter profile platinum add cir 46000000 pir 138000000 cbs 1000000 pbs 1000000
 pipeline PIPELINE0 meter meters from 0 to 15 set profile platinum
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/mirroring.cli b/examples/pipeline/examples/mirroring.cli
index 46d57db4ec..1d439e04d3 100644
--- a/examples/pipeline/examples/mirroring.cli
+++ b/examples/pipeline/examples/mirroring.cli
@@ -1,36 +1,38 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/mirroring.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/mirroring.spec /tmp/mirroring.c
+pipeline libbuild /tmp/mirroring.c /tmp/mirroring.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-pipeline PIPELINE0 mirror slots 4 sessions 16
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/mirroring.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/mirroring.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
-; Packet mirroring sessions.
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
 ;
 pipeline PIPELINE0 mirror session 0 port 1 clone fast truncate 0
 pipeline PIPELINE0 mirror session 1 port 2 clone slow truncate 0
diff --git a/examples/pipeline/examples/pcap.io b/examples/pipeline/examples/pcap.io
new file mode 100644
index 0000000000..111f61afae
--- /dev/null
+++ b/examples/pipeline/examples/pcap.io
@@ -0,0 +1,27 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2022 Intel Corporation
+
+;
+; Pipeline packet mirroring.
+;
+mirroring slots 4 sessions 64
+
+;
+; Pipeline input ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port in 0 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 1 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 2 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 3 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+
+;
+; Pipeline output ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port out 0 sink file none
+port out 1 sink file none
+port out 2 sink file none
+port out 3 sink file none
diff --git a/examples/pipeline/examples/recirculation.cli b/examples/pipeline/examples/recirculation.cli
index f855c5c327..52d0894f12 100644
--- a/examples/pipeline/examples/recirculation.cli
+++ b/examples/pipeline/examples/recirculation.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/recirculation.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/recirculation.spec /tmp/recirculation.c
+pipeline libbuild /tmp/recirculation.c /tmp/recirculation.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/recirculation.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/recirculation.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/registers.cli b/examples/pipeline/examples/registers.cli
index 8d026294cb..3516f76a5b 100644
--- a/examples/pipeline/examples/registers.cli
+++ b/examples/pipeline/examples/registers.cli
@@ -1,28 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-; Example command line:
-;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/registers.cli
-
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/registers.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/registers.spec /tmp/registers.c
+pipeline libbuild /tmp/registers.c /tmp/registers.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/registers.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/registers.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/selector.cli b/examples/pipeline/examples/selector.cli
index 123782c57b..f0e251b657 100644
--- a/examples/pipeline/examples/selector.cli
+++ b/examples/pipeline/examples/selector.cli
@@ -1,30 +1,45 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/selector.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/selector.spec /tmp/selector.c
+pipeline libbuild /tmp/selector.c /tmp/selector.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/selector.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/selector.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 selector s group add
 pipeline PIPELINE0 selector s group member add ./examples/pipeline/examples/selector.txt
 pipeline PIPELINE0 commit
 pipeline PIPELINE0 selector s show
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/varbit.cli b/examples/pipeline/examples/varbit.cli
index 9caeb9ca26..0f89990471 100644
--- a/examples/pipeline/examples/varbit.cli
+++ b/examples/pipeline/examples/varbit.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/varbit.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/varbit.spec /tmp/varbit.c
+pipeline libbuild /tmp/varbit.c /tmp/varbit.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/varbit.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/varbit.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/vxlan.cli b/examples/pipeline/examples/vxlan.cli
index 444f3f7bd8..1fbd1be6e4 100644
--- a/examples/pipeline/examples/vxlan.cli
+++ b/examples/pipeline/examples/vxlan.cli
@@ -1,27 +1,43 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/vxlan.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/vxlan.so io ./examples/pipeline/examples/ethdev.io numa 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/vxlan_pcap.cli b/examples/pipeline/examples/vxlan_pcap.cli
index 83fca8d0d9..adc7f73312 100644
--- a/examples/pipeline/examples/vxlan_pcap.cli
+++ b/examples/pipeline/examples/vxlan_pcap.cli
@@ -1,22 +1,39 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/vxlan_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/vxlan.so io ./examples/pipeline/examples/pcap.io numa 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 01/17] pipeline: add pipeline name
  2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
                       ` (15 preceding siblings ...)
  2022-07-27 22:36     ` [PATCH V3 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
@ 2022-07-27 22:54     ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
                         ` (16 more replies)
  16 siblings, 17 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add an unique name to every pipeline. This enables the library to
maintain a list of the existing pipeline objects, which can be
queried by the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/obj.c                  |   2 +-
 lib/pipeline/rte_swx_ctl.c               |  99 +++++++++++++++++++++
 lib/pipeline/rte_swx_ctl.h               |  15 ++++
 lib/pipeline/rte_swx_pipeline.c          | 107 ++++++++++++++++++++++-
 lib/pipeline/rte_swx_pipeline.h          |  18 +++-
 lib/pipeline/rte_swx_pipeline_internal.h |   2 +
 lib/pipeline/version.map                 |   4 +
 7 files changed, 244 insertions(+), 3 deletions(-)

diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index b79f044ac7..967342c580 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -533,7 +533,7 @@ pipeline_create(struct obj *obj, const char *name, int numa_node)
 		return NULL;
 
 	/* Resource create */
-	status = rte_swx_pipeline_config(&p, numa_node);
+	status = rte_swx_pipeline_config(&p, name, numa_node);
 	if (status)
 		goto error;
 
diff --git a/lib/pipeline/rte_swx_ctl.c b/lib/pipeline/rte_swx_ctl.c
index 710e89a46a..1b776fc543 100644
--- a/lib/pipeline/rte_swx_ctl.c
+++ b/lib/pipeline/rte_swx_ctl.c
@@ -9,6 +9,8 @@
 
 #include <rte_common.h>
 #include <rte_byteorder.h>
+#include <rte_tailq.h>
+#include <rte_eal_memconfig.h>
 
 #include <rte_swx_table_selector.h>
 
@@ -1157,12 +1159,103 @@ table_state_create(struct rte_swx_ctl_pipeline *ctl)
 	return status;
 }
 
+/* Global list of pipeline instances. */
+TAILQ_HEAD(rte_swx_ctl_pipeline_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_swx_ctl_pipeline_tailq = {
+	.name = "RTE_SWX_CTL_PIPELINE",
+};
+
+EAL_REGISTER_TAILQ(rte_swx_ctl_pipeline_tailq)
+
+struct rte_swx_ctl_pipeline *
+rte_swx_ctl_pipeline_find(const char *name)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	if (!name || !name[0] || (strnlen(name, RTE_SWX_CTL_NAME_SIZE) >= RTE_SWX_CTL_NAME_SIZE))
+		return NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_read_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		struct rte_swx_ctl_pipeline *ctl = (struct rte_swx_ctl_pipeline *)te->data;
+
+		if (!strncmp(name, ctl->info.name, sizeof(ctl->info.name))) {
+			rte_mcfg_tailq_read_unlock();
+			return ctl;
+		}
+	}
+
+	rte_mcfg_tailq_read_unlock();
+	return NULL;
+}
+
+static int
+ctl_register(struct rte_swx_ctl_pipeline *ctl)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		struct rte_swx_ctl_pipeline *ctl_crt = (struct rte_swx_ctl_pipeline *)te->data;
+
+		if (!strncmp(ctl->info.name, ctl_crt->info.name, sizeof(ctl->info.name))) {
+			rte_mcfg_tailq_write_unlock();
+			return -EEXIST;
+		}
+	}
+
+	te = calloc(1, sizeof(struct rte_tailq_entry));
+	if (!te) {
+		rte_mcfg_tailq_write_unlock();
+		return -ENOMEM;
+	}
+
+	te->data = (void *)ctl;
+	TAILQ_INSERT_TAIL(ctl_list, te, next);
+	rte_mcfg_tailq_write_unlock();
+	return 0;
+}
+
+static void
+ctl_unregister(struct rte_swx_ctl_pipeline *ctl)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		if (te->data == (void *)ctl) {
+			TAILQ_REMOVE(ctl_list, te, next);
+			rte_mcfg_tailq_write_unlock();
+			free(te);
+			return;
+		}
+	}
+
+	rte_mcfg_tailq_write_unlock();
+}
+
 void
 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
 {
 	if (!ctl)
 		return;
 
+	if (ctl->info.name[0])
+		ctl_unregister(ctl);
+
 	action_free(ctl);
 
 	table_state_free(ctl);
@@ -1441,6 +1534,12 @@ rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
 	if (status)
 		goto error;
 
+	if (ctl->info.name[0]) {
+		status = ctl_register(ctl);
+		if (status)
+			goto error;
+	}
+
 	return ctl;
 
 error:
diff --git a/lib/pipeline/rte_swx_ctl.h b/lib/pipeline/rte_swx_ctl.h
index d771389d26..63ee479e47 100644
--- a/lib/pipeline/rte_swx_ctl.h
+++ b/lib/pipeline/rte_swx_ctl.h
@@ -35,6 +35,9 @@ struct rte_swx_pipeline;
 
 /** Pipeline info. */
 struct rte_swx_ctl_pipeline_info {
+	/** Pipeline name. */
+	char name[RTE_SWX_CTL_NAME_SIZE];
+
 	/** Number of input ports. */
 	uint32_t n_ports_in;
 
@@ -812,6 +815,18 @@ rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p,
 /** Pipeline control opaque data structure. */
 struct rte_swx_ctl_pipeline;
 
+/**
+ * Pipeline control find
+ *
+ * @param[in] name
+ *   Pipeline name.
+ * @return
+ *   Valid pipeline control handle if found or NULL otherwise.
+ */
+__rte_experimental
+struct rte_swx_ctl_pipeline *
+rte_swx_ctl_pipeline_find(const char *name);
+
 /**
  * Pipeline control create
  *
diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index 3e1c6e9edb..c8ccded4f8 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -6,6 +6,8 @@
 #include <errno.h>
 #include <dlfcn.h>
 
+#include <rte_tailq.h>
+#include <rte_eal_memconfig.h>
 #include <rte_jhash.h>
 #include <rte_hash_crc.h>
 
@@ -9578,6 +9580,95 @@ metarray_free(struct rte_swx_pipeline *p)
 /*
  * Pipeline.
  */
+
+/* Global list of pipeline instances. */
+TAILQ_HEAD(rte_swx_pipeline_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_swx_pipeline_tailq = {
+	.name = "RTE_SWX_PIPELINE",
+};
+
+EAL_REGISTER_TAILQ(rte_swx_pipeline_tailq)
+
+struct rte_swx_pipeline *
+rte_swx_pipeline_find(const char *name)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	if (!name || !name[0] || (strnlen(name, RTE_SWX_NAME_SIZE) >= RTE_SWX_NAME_SIZE))
+		return NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_read_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		struct rte_swx_pipeline *p = (struct rte_swx_pipeline *)te->data;
+
+		if (!strncmp(name, p->name, sizeof(p->name))) {
+			rte_mcfg_tailq_read_unlock();
+			return p;
+		}
+	}
+
+	rte_mcfg_tailq_read_unlock();
+	return NULL;
+}
+
+static int
+pipeline_register(struct rte_swx_pipeline *p)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		struct rte_swx_pipeline *pipeline = (struct rte_swx_pipeline *)te->data;
+
+		if (!strncmp(p->name, pipeline->name, sizeof(p->name))) {
+			rte_mcfg_tailq_write_unlock();
+			return -EEXIST;
+		}
+	}
+
+	te = calloc(1, sizeof(struct rte_tailq_entry));
+	if (!te) {
+		rte_mcfg_tailq_write_unlock();
+		return -ENOMEM;
+	}
+
+	te->data = (void *)p;
+	TAILQ_INSERT_TAIL(pipeline_list, te, next);
+	rte_mcfg_tailq_write_unlock();
+	return 0;
+}
+
+static void
+pipeline_unregister(struct rte_swx_pipeline *p)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		if (te->data == (void *)p) {
+			TAILQ_REMOVE(pipeline_list, te, next);
+			rte_mcfg_tailq_write_unlock();
+			free(te);
+			return;
+		}
+	}
+
+	rte_mcfg_tailq_write_unlock();
+}
+
 void
 rte_swx_pipeline_free(struct rte_swx_pipeline *p)
 {
@@ -9586,6 +9677,9 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p)
 	if (!p)
 		return;
 
+	if (p->name[0])
+		pipeline_unregister(p);
+
 	lib = p->lib;
 
 	free(p->instruction_data);
@@ -9720,13 +9814,14 @@ hash_funcs_register(struct rte_swx_pipeline *p)
 }
 
 int
-rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
+rte_swx_pipeline_config(struct rte_swx_pipeline **p, const char *name, int numa_node)
 {
 	struct rte_swx_pipeline *pipeline = NULL;
 	int status = 0;
 
 	/* Check input parameters. */
 	CHECK(p, EINVAL);
+	CHECK(!name || (strnlen(name, RTE_SWX_NAME_SIZE) < RTE_SWX_NAME_SIZE), EINVAL);
 
 	/* Memory allocation. */
 	pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
@@ -9736,6 +9831,9 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
 	}
 
 	/* Initialization. */
+	if (name)
+		strcpy(pipeline->name, name);
+
 	TAILQ_INIT(&pipeline->struct_types);
 	TAILQ_INIT(&pipeline->port_in_types);
 	TAILQ_INIT(&pipeline->ports_in);
@@ -9776,6 +9874,12 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
 	if (status)
 		goto error;
 
+	if (pipeline->name[0]) {
+		status = pipeline_register(pipeline);
+		if (status)
+			goto error;
+	}
+
 	*p = pipeline;
 	return 0;
 
@@ -9966,6 +10070,7 @@ rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p,
 	TAILQ_FOREACH(table, &p->tables, node)
 		n_tables++;
 
+	strcpy(pipeline->name, p->name);
 	pipeline->n_ports_in = p->n_ports_in;
 	pipeline->n_ports_out = p->n_ports_out;
 	pipeline->n_mirroring_slots = p->n_mirroring_slots;
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index c41ca5cb15..ef50a0fa70 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -44,22 +44,38 @@ extern "C" {
 /** Pipeline opaque data structure. */
 struct rte_swx_pipeline;
 
+/**
+ * Pipeline find
+ *
+ * @param[in] name
+ *   Pipeline name.
+ * @return
+ *   Valid pipeline handle if found or NULL otherwise.
+ */
+__rte_experimental
+struct rte_swx_pipeline *
+rte_swx_pipeline_find(const char *name);
+
 /**
  * Pipeline configure
  *
  * @param[out] p
  *   Pipeline handle. Must point to valid memory. Contains valid pipeline handle
  *   when the function returns successfully.
+ * @param[in] name
+ *   Pipeline unique name.
  * @param[in] numa_node
  *   Non-Uniform Memory Access (NUMA) node.
  * @return
  *   0 on success or the following error codes otherwise:
  *   -EINVAL: Invalid argument;
- *   -ENOMEM: Not enough space/cannot allocate memory.
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -EEXIST: Pipeline with this name already exists.
  */
 __rte_experimental
 int
 rte_swx_pipeline_config(struct rte_swx_pipeline **p,
+			const char *name,
 			int numa_node);
 
 /*
diff --git a/lib/pipeline/rte_swx_pipeline_internal.h b/lib/pipeline/rte_swx_pipeline_internal.h
index a35635efb7..588cad62b5 100644
--- a/lib/pipeline/rte_swx_pipeline_internal.h
+++ b/lib/pipeline/rte_swx_pipeline_internal.h
@@ -1459,6 +1459,8 @@ instr_operand_nbo(struct thread *t, const struct instr_operand *x)
 #endif
 
 struct rte_swx_pipeline {
+	char name[RTE_SWX_NAME_SIZE];
+
 	struct struct_type_tailq struct_types;
 	struct port_in_type_tailq port_in_types;
 	struct port_in_tailq ports_in;
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 8312307a7a..50029aadcf 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -145,4 +145,8 @@ EXPERIMENTAL {
 	rte_swx_ctl_pipeline_learner_timeout_get;
 	rte_swx_ctl_pipeline_learner_timeout_set;
 	rte_swx_pipeline_hash_func_register;
+
+	#added in 22.11
+	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 02/17] pipeline: move specification data structures to internal header
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
                         ` (15 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Move all the pipeline object specification data structures to an
internal header file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 126 +------------------
 lib/pipeline/rte_swx_pipeline_spec.h | 176 +++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 125 deletions(-)
 create mode 100644 lib/pipeline/rte_swx_pipeline_spec.h

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 904b9eb471..5e07b4f794 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -9,7 +9,7 @@
 
 #include <rte_common.h>
 
-#include "rte_swx_pipeline.h"
+#include "rte_swx_pipeline_spec.h"
 
 #ifndef MAX_LINE_LENGTH
 #define MAX_LINE_LENGTH 2048
@@ -34,15 +34,7 @@
 
 /*
  * extobj.
- *
- * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
  */
-struct extobj_spec {
-	char *name;
-	char *extern_type_name;
-	char *pragma;
-};
-
 static void
 extobj_spec_free(struct extobj_spec *s)
 {
@@ -104,18 +96,7 @@ extobj_statement_parse(struct extobj_spec *s,
 /*
  * struct.
  *
- * struct STRUCT_TYPE_NAME {
- *	bit<SIZE> | varbit<SIZE> FIELD_NAME
- *	...
- * }
  */
-struct struct_spec {
-	char *name;
-	struct rte_swx_field_params *fields;
-	uint32_t n_fields;
-	int varbit;
-};
-
 static void
 struct_spec_free(struct struct_spec *s)
 {
@@ -293,13 +274,7 @@ struct_block_parse(struct struct_spec *s,
 /*
  * header.
  *
- * header HEADER_NAME instanceof STRUCT_TYPE_NAME
  */
-struct header_spec {
-	char *name;
-	char *struct_type_name;
-};
-
 static void
 header_spec_free(struct header_spec *s)
 {
@@ -351,12 +326,7 @@ header_statement_parse(struct header_spec *s,
 /*
  * metadata.
  *
- * metadata instanceof STRUCT_TYPE_NAME
  */
-struct metadata_spec {
-	char *struct_type_name;
-};
-
 static void
 metadata_spec_free(struct metadata_spec *s)
 {
@@ -400,18 +370,7 @@ metadata_statement_parse(struct metadata_spec *s,
 /*
  * action.
  *
- * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
- *	INSTRUCTION
- *	...
- * }
  */
-struct action_spec {
-	char *name;
-	char *args_struct_type_name;
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 action_spec_free(struct action_spec *s)
 {
@@ -540,29 +499,7 @@ action_block_parse(struct action_spec *s,
 /*
  * table.
  *
- * table TABLE_NAME {
- *	key {
- *		MATCH_FIELD_NAME exact | wildcard | lpm
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly ]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	instanceof TABLE_TYPE_NAME
- *	pragma ARGS
- *	size SIZE
- * }
  */
-struct table_spec {
-	char *name;
-	struct rte_swx_pipeline_table_params params;
-	char *recommended_table_type_name;
-	char *args;
-	uint32_t size;
-};
-
 static void
 table_spec_free(struct table_spec *s)
 {
@@ -1084,22 +1021,7 @@ table_block_parse(struct table_spec *s,
 /*
  * selector.
  *
- * selector SELECTOR_NAME {
- *	group_id FIELD_NAME
- *	selector {
- *		FIELD_NAME
- *		...
- *	}
- *	member_id FIELD_NAME
- *	n_groups N_GROUPS
- *	n_members_per_group N_MEMBERS_PER_GROUP
- * }
  */
-struct selector_spec {
-	char *name;
-	struct rte_swx_pipeline_selector_params params;
-};
-
 static void
 selector_spec_free(struct selector_spec *s)
 {
@@ -1385,31 +1307,7 @@ selector_block_parse(struct selector_spec *s,
 /*
  * learner.
  *
- * learner LEARNER_NAME {
- *	key {
- *		MATCH_FIELD_NAME
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	size SIZE
- *	timeout {
- *		TIMEOUT_IN_SECONDS
- *		...
- *	}
- * }
  */
-struct learner_spec {
-	char *name;
-	struct rte_swx_pipeline_learner_params params;
-	uint32_t size;
-	uint32_t *timeout;
-	uint32_t n_timeouts;
-};
-
 static void
 learner_spec_free(struct learner_spec *s)
 {
@@ -1958,14 +1856,7 @@ learner_block_parse(struct learner_spec *s,
 /*
  * regarray.
  *
- * regarray NAME size SIZE initval INITVAL
  */
-struct regarray_spec {
-	char *name;
-	uint64_t init_val;
-	uint32_t size;
-};
-
 static void
 regarray_spec_free(struct regarray_spec *s)
 {
@@ -2033,13 +1924,7 @@ regarray_statement_parse(struct regarray_spec *s,
 /*
  * metarray.
  *
- * metarray NAME size SIZE
  */
-struct metarray_spec {
-	char *name;
-	uint32_t size;
-};
-
 static void
 metarray_spec_free(struct metarray_spec *s)
 {
@@ -2095,16 +1980,7 @@ metarray_statement_parse(struct metarray_spec *s,
 /*
  * apply.
  *
- * apply {
- *	INSTRUCTION
- *	...
- * }
  */
-struct apply_spec {
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 apply_spec_free(struct apply_spec *s)
 {
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
new file mode 100644
index 0000000000..8458de878a
--- /dev/null
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Intel Corporation
+ */
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_common.h>
+
+#include <rte_swx_pipeline.h>
+
+/*
+ * extobj.
+ *
+ * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
+ */
+struct extobj_spec {
+	char *name;
+	char *extern_type_name;
+	char *pragma;
+};
+
+/*
+ * struct.
+ *
+ * struct STRUCT_TYPE_NAME {
+ *	bit<SIZE> | varbit<SIZE> FIELD_NAME
+ *	...
+ * }
+ */
+struct struct_spec {
+	char *name;
+	struct rte_swx_field_params *fields;
+	uint32_t n_fields;
+	int varbit;
+};
+
+/*
+ * header.
+ *
+ * header HEADER_NAME instanceof STRUCT_TYPE_NAME
+ */
+struct header_spec {
+	char *name;
+	char *struct_type_name;
+};
+
+/*
+ * metadata.
+ *
+ * metadata instanceof STRUCT_TYPE_NAME
+ */
+struct metadata_spec {
+	char *struct_type_name;
+};
+
+/*
+ * action.
+ *
+ * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct action_spec {
+	char *name;
+	char *args_struct_type_name;
+	const char **instructions;
+	uint32_t n_instructions;
+};
+
+/*
+ * table.
+ *
+ * table TABLE_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME exact | wildcard | lpm
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly ]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	instanceof TABLE_TYPE_NAME
+ *	pragma ARGS
+ *	size SIZE
+ * }
+ */
+struct table_spec {
+	char *name;
+	struct rte_swx_pipeline_table_params params;
+	char *recommended_table_type_name;
+	char *args;
+	uint32_t size;
+};
+
+/*
+ * selector.
+ *
+ * selector SELECTOR_NAME {
+ *	group_id FIELD_NAME
+ *	selector {
+ *		FIELD_NAME
+ *		...
+ *	}
+ *	member_id FIELD_NAME
+ *	n_groups N_GROUPS
+ *	n_members_per_group N_MEMBERS_PER_GROUP
+ * }
+ */
+struct selector_spec {
+	char *name;
+	struct rte_swx_pipeline_selector_params params;
+};
+
+/*
+ * learner.
+ *
+ * learner LEARNER_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	size SIZE
+ *	timeout {
+ *		TIMEOUT_IN_SECONDS
+ *		...
+ *	}
+ * }
+ */
+struct learner_spec {
+	char *name;
+	struct rte_swx_pipeline_learner_params params;
+	uint32_t size;
+	uint32_t *timeout;
+	uint32_t n_timeouts;
+};
+
+/*
+ * regarray.
+ *
+ * regarray NAME size SIZE initval INITVAL
+ */
+struct regarray_spec {
+	char *name;
+	uint64_t init_val;
+	uint32_t size;
+};
+
+/*
+ * metarray.
+ *
+ * metarray NAME size SIZE
+ */
+struct metarray_spec {
+	char *name;
+	uint32_t size;
+};
+
+/*
+ * apply.
+ *
+ * apply {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct apply_spec {
+	const char **instructions;
+	uint32_t n_instructions;
+};
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 03/17] pipeline: add pipeline specification data structure
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
                         ` (14 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add specification data structure for the entire pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 21 ++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h | 32 ++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 5e07b4f794..642091b678 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2082,6 +2082,27 @@ apply_block_parse(struct apply_spec *s,
 /*
  * Pipeline.
  */
+void
+pipeline_spec_free(struct pipeline_spec *s)
+{
+	if (!s)
+		return;
+
+	free(s->extobjs);
+	free(s->structs);
+	free(s->headers);
+	free(s->metadata);
+	free(s->actions);
+	free(s->tables);
+	free(s->selectors);
+	free(s->learners);
+	free(s->regarrays);
+	free(s->metarrays);
+	free(s->apply);
+
+	memset(s, 0, sizeof(struct pipeline_spec));
+}
+
 int
 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				 FILE *spec,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 8458de878a..e1170a33b1 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -174,3 +174,35 @@ struct apply_spec {
 	const char **instructions;
 	uint32_t n_instructions;
 };
+
+/*
+ * Pipeline.
+ */
+struct pipeline_spec {
+	struct extobj_spec *extobjs;
+	struct struct_spec *structs;
+	struct header_spec *headers;
+	struct metadata_spec *metadata;
+	struct action_spec *actions;
+	struct table_spec *tables;
+	struct selector_spec *selectors;
+	struct learner_spec *learners;
+	struct regarray_spec *regarrays;
+	struct metarray_spec *metarrays;
+	struct apply_spec *apply;
+
+	uint32_t n_extobjs;
+	uint32_t n_structs;
+	uint32_t n_headers;
+	uint32_t n_metadata;
+	uint32_t n_actions;
+	uint32_t n_tables;
+	uint32_t n_selectors;
+	uint32_t n_learners;
+	uint32_t n_regarrays;
+	uint32_t n_metarrays;
+	uint32_t n_apply;
+};
+
+void
+pipeline_spec_free(struct pipeline_spec *s);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 04/17] pipeline: rework the specification file-based pipeline build
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
                         ` (13 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Rework the specification file-based pipeline build operation to first
parse the specification file into the previously introduced pipeline
specification data structure, then use this structure to configure
and build the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 478 +++++++++++++++++++++------
 lib/pipeline/rte_swx_pipeline_spec.h |   9 +
 2 files changed, 385 insertions(+), 102 deletions(-)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 642091b678..62929a9da6 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2103,11 +2103,10 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg)
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg)
 {
 	struct extobj_spec extobj_spec = {0};
 	struct struct_spec struct_spec = {0};
@@ -2120,26 +2119,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	struct regarray_spec regarray_spec = {0};
 	struct metarray_spec metarray_spec = {0};
 	struct apply_spec apply_spec = {0};
-	uint32_t n_lines;
+	struct pipeline_spec *s = NULL;
+	uint32_t n_lines = 0;
 	uint32_t block_mask = 0;
-	int status;
+	int status = 0;
 
 	/* Check the input arguments. */
-	if (!p) {
+	if (!spec) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null pipeline argument.";
+			*err_msg = "Invalid input argument.";
 		status = -EINVAL;
 		goto error;
 	}
 
-	if (!spec) {
+	/* Memory allocation. */
+	s = calloc(sizeof(struct pipeline_spec), 1);
+	if (!s) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null specification file argument.";
-		status = -EINVAL;
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
 		goto error;
 	}
 
@@ -2200,6 +2202,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* struct block. */
 		if (block_mask & (1 << STRUCT_BLOCK)) {
+			struct struct_spec *new_structs;
+
 			status = struct_block_parse(&struct_spec,
 						    &block_mask,
 						    tokens,
@@ -2214,26 +2218,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_struct_type_register(p,
-				struct_spec.name,
-				struct_spec.fields,
-				struct_spec.n_fields,
-				struct_spec.varbit);
-			if (status) {
+			new_structs = realloc(s->structs,
+					      (s->n_structs + 1) * sizeof(struct struct_spec));
+			if (!new_structs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Struct registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			struct_spec_free(&struct_spec);
+			s->structs = new_structs;
+			memcpy(&s->structs[s->n_structs], &struct_spec, sizeof(struct struct_spec));
+			s->n_structs++;
+			memset(&struct_spec, 0, sizeof(struct struct_spec));
 
 			continue;
 		}
 
 		/* action block. */
 		if (block_mask & (1 << ACTION_BLOCK)) {
+			struct action_spec *new_actions;
+
 			status = action_block_parse(&action_spec,
 						    &block_mask,
 						    tokens,
@@ -2248,26 +2255,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_action_config(p,
-				action_spec.name,
-				action_spec.args_struct_type_name,
-				action_spec.instructions,
-				action_spec.n_instructions);
-			if (status) {
+			new_actions = realloc(s->actions,
+					      (s->n_actions + 1) * sizeof(struct action_spec));
+			if (!new_actions) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Action config error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			action_spec_free(&action_spec);
+			s->actions = new_actions;
+			memcpy(&s->actions[s->n_actions], &action_spec, sizeof(struct action_spec));
+			s->n_actions++;
+			memset(&action_spec, 0, sizeof(struct action_spec));
 
 			continue;
 		}
 
 		/* table block. */
 		if (block_mask & (1 << TABLE_BLOCK)) {
+			struct table_spec *new_tables;
+
 			status = table_block_parse(&table_spec,
 						   &block_mask,
 						   tokens,
@@ -2282,27 +2292,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_table_config(p,
-				table_spec.name,
-				&table_spec.params,
-				table_spec.recommended_table_type_name,
-				table_spec.args,
-				table_spec.size);
-			if (status) {
+			new_tables = realloc(s->tables,
+					     (s->n_tables + 1) * sizeof(struct table_spec));
+			if (!new_tables) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			table_spec_free(&table_spec);
+			s->tables = new_tables;
+			memcpy(&s->tables[s->n_tables], &table_spec, sizeof(struct table_spec));
+			s->n_tables++;
+			memset(&table_spec, 0, sizeof(struct table_spec));
 
 			continue;
 		}
 
 		/* selector block. */
 		if (block_mask & (1 << SELECTOR_BLOCK)) {
+			struct selector_spec *new_selectors;
+
 			status = selector_block_parse(&selector_spec,
 						      &block_mask,
 						      tokens,
@@ -2317,24 +2329,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_selector_config(p,
-				selector_spec.name,
-				&selector_spec.params);
-			if (status) {
+			new_selectors = realloc(s->selectors,
+				(s->n_selectors + 1) * sizeof(struct selector_spec));
+			if (!new_selectors) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Selector configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			selector_spec_free(&selector_spec);
+			s->selectors = new_selectors;
+			memcpy(&s->selectors[s->n_selectors],
+			       &selector_spec,
+			       sizeof(struct selector_spec));
+			s->n_selectors++;
+			memset(&selector_spec, 0, sizeof(struct selector_spec));
 
 			continue;
 		}
 
 		/* learner block. */
 		if (block_mask & (1 << LEARNER_BLOCK)) {
+			struct learner_spec *new_learners;
+
 			status = learner_block_parse(&learner_spec,
 						     &block_mask,
 						     tokens,
@@ -2349,27 +2368,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_learner_config(p,
-				learner_spec.name,
-				&learner_spec.params,
-				learner_spec.size,
-				learner_spec.timeout,
-				learner_spec.n_timeouts);
-			if (status) {
+			new_learners = realloc(s->learners,
+					       (s->n_learners + 1) * sizeof(struct learner_spec));
+			if (!new_learners) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Learner table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			learner_spec_free(&learner_spec);
+			s->learners = new_learners;
+			memcpy(&s->learners[s->n_learners],
+			       &learner_spec,
+			       sizeof(struct learner_spec));
+			s->n_learners++;
+			memset(&learner_spec, 0, sizeof(struct learner_spec));
 
 			continue;
 		}
 
 		/* apply block. */
 		if (block_mask & (1 << APPLY_BLOCK)) {
+			struct apply_spec *new_apply;
+
 			status = apply_block_parse(&apply_spec,
 						   &block_mask,
 						   tokens,
@@ -2384,24 +2407,28 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_instructions_config(p,
-				apply_spec.instructions,
-				apply_spec.n_instructions);
-			if (status) {
+			new_apply = realloc(s->apply, (s->n_apply + 1) * sizeof(struct apply_spec));
+			if (!new_apply) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Pipeline instructions err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			apply_spec_free(&apply_spec);
+			s->apply = new_apply;
+			memcpy(&s->apply[s->n_apply], &apply_spec, sizeof(struct apply_spec));
+			s->n_apply++;
+			memset(&apply_spec, 0, sizeof(struct apply_spec));
 
 			continue;
 		}
 
 		/* extobj. */
 		if (!strcmp(tokens[0], "extobj")) {
+			struct extobj_spec *new_extobjs;
+
 			status = extobj_statement_parse(&extobj_spec,
 							tokens,
 							n_tokens,
@@ -2411,19 +2438,21 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_extern_object_config(p,
-				extobj_spec.name,
-				extobj_spec.extern_type_name,
-				extobj_spec.pragma);
-			if (status) {
+			new_extobjs = realloc(s->extobjs,
+					      (s->n_extobjs + 1) * sizeof(struct extobj_spec));
+			if (!new_extobjs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Extern object config err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			extobj_spec_free(&extobj_spec);
+			s->extobjs = new_extobjs;
+			memcpy(&s->extobjs[s->n_extobjs], &extobj_spec, sizeof(struct extobj_spec));
+			s->n_extobjs++;
+			memset(&extobj_spec, 0, sizeof(struct extobj_spec));
 
 			continue;
 		}
@@ -2445,6 +2474,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* header. */
 		if (!strcmp(tokens[0], "header")) {
+			struct header_spec *new_headers;
+
 			status = header_statement_parse(&header_spec,
 							tokens,
 							n_tokens,
@@ -2454,24 +2485,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_header_register(p,
-				header_spec.name,
-				header_spec.struct_type_name);
-			if (status) {
+			new_headers = realloc(s->headers,
+					      (s->n_headers + 1) * sizeof(struct header_spec));
+			if (!new_headers) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Header registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			header_spec_free(&header_spec);
+			s->headers = new_headers;
+			memcpy(&s->headers[s->n_headers], &header_spec, sizeof(struct header_spec));
+			s->n_headers++;
+			memset(&header_spec, 0, sizeof(struct header_spec));
 
 			continue;
 		}
 
 		/* metadata. */
 		if (!strcmp(tokens[0], "metadata")) {
+			struct metadata_spec *new_metadata;
+
 			status = metadata_statement_parse(&metadata_spec,
 							  tokens,
 							  n_tokens,
@@ -2481,17 +2517,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_metadata_register(p,
-				metadata_spec.struct_type_name);
-			if (status) {
+			new_metadata = realloc(s->metadata,
+					       (s->n_metadata + 1) * sizeof(struct metadata_spec));
+			if (!new_metadata) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meta-data reg err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metadata_spec_free(&metadata_spec);
+			s->metadata = new_metadata;
+			memcpy(&s->metadata[s->n_metadata],
+			       &metadata_spec,
+			       sizeof(struct metadata_spec));
+			s->n_metadata++;
+			memset(&metadata_spec, 0, sizeof(struct metadata_spec));
 
 			continue;
 		}
@@ -2558,6 +2600,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* regarray. */
 		if (!strcmp(tokens[0], "regarray")) {
+			struct regarray_spec *new_regarrays;
+
 			status = regarray_statement_parse(&regarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2567,25 +2611,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_regarray_config(p,
-				regarray_spec.name,
-				regarray_spec.size,
-				regarray_spec.init_val);
-			if (status) {
+			new_regarrays = realloc(s->regarrays,
+				(s->n_regarrays + 1) * sizeof(struct regarray_spec));
+			if (!new_regarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Register array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			regarray_spec_free(&regarray_spec);
+			s->regarrays = new_regarrays;
+			memcpy(&s->regarrays[s->n_regarrays],
+			       &regarray_spec,
+			       sizeof(struct regarray_spec));
+			s->n_regarrays++;
+			memset(&regarray_spec, 0, sizeof(struct regarray_spec));
 
 			continue;
 		}
 
 		/* metarray. */
 		if (!strcmp(tokens[0], "metarray")) {
+			struct metarray_spec *new_metarrays;
+
 			status = metarray_statement_parse(&metarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2595,18 +2645,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_metarray_config(p,
-				metarray_spec.name,
-				metarray_spec.size);
-			if (status) {
+			new_metarrays = realloc(s->metarrays,
+				(s->n_metarrays + 1) * sizeof(struct metarray_spec));
+			if (!new_metarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meter array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metarray_spec_free(&metarray_spec);
+			s->metarrays = new_metarrays;
+			memcpy(&s->metarrays[s->n_metarrays],
+			       &metarray_spec,
+			       sizeof(struct metarray_spec));
+			s->n_metarrays++;
+			memset(&metarray_spec, 0, sizeof(struct metarray_spec));
 
 			continue;
 		}
@@ -2644,17 +2699,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 		goto error;
 	}
 
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = n_lines;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
+	return s;
 
 error:
 	extobj_spec_free(&extobj_spec);
@@ -2668,5 +2713,234 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	regarray_spec_free(&regarray_spec);
 	metarray_spec_free(&metarray_spec);
 	apply_spec_free(&apply_spec);
+	pipeline_spec_free(s);
+
+	return NULL;
+}
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg)
+{
+	uint32_t i;
+	int status = 0;
+
+	/* extobj. */
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		status = rte_swx_pipeline_extern_object_config(p,
+			extobj_spec->name,
+			extobj_spec->extern_type_name,
+			extobj_spec->pragma);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Extern object configuration error.";
+			return status;
+		}
+	}
+
+	/* regarray. */
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		status = rte_swx_pipeline_regarray_config(p,
+			regarray_spec->name,
+			regarray_spec->size,
+			regarray_spec->init_val);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Register array configuration error.";
+			return status;
+		}
+	}
+
+	/* metarray. */
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		status = rte_swx_pipeline_metarray_config(p,
+			metarray_spec->name,
+			metarray_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meter array configuration error.";
+			return status;
+		}
+	}
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		status = rte_swx_pipeline_struct_type_register(p,
+			struct_spec->name,
+			struct_spec->fields,
+			struct_spec->n_fields,
+			struct_spec->varbit);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Struct type registration error.";
+			return status;
+		}
+	}
+
+	/* header. */
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		status = rte_swx_pipeline_packet_header_register(p,
+			header_spec->name,
+			header_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Header configuration error.";
+			return status;
+		}
+	}
+
+	/* metadata. */
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		status = rte_swx_pipeline_packet_metadata_register(p,
+			metadata_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meta-data registration error.";
+			return status;
+		}
+	}
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		status = rte_swx_pipeline_action_config(p,
+			action_spec->name,
+			action_spec->args_struct_type_name,
+			action_spec->instructions,
+			action_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Action configuration error.";
+			return status;
+		}
+	}
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		status = rte_swx_pipeline_table_config(p,
+			table_spec->name,
+			&table_spec->params,
+			table_spec->recommended_table_type_name,
+			table_spec->args,
+			table_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Table configuration error.";
+			return status;
+		}
+	}
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		status = rte_swx_pipeline_selector_config(p,
+			selector_spec->name,
+			&selector_spec->params);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Selector table configuration error.";
+			return status;
+		}
+	}
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		status = rte_swx_pipeline_learner_config(p,
+			learner_spec->name,
+			&learner_spec->params,
+			learner_spec->size,
+			learner_spec->timeout,
+			learner_spec->n_timeouts);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Learner table configuration error.";
+			return status;
+		}
+	}
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+
+		status = rte_swx_pipeline_instructions_config(p,
+			apply_spec->instructions,
+			apply_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline instructions configuration error.";
+			return status;
+		}
+	}
+
+	return 0;
+}
+
+int
+rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
+				 FILE *spec_file,
+				 uint32_t *err_line,
+				 const char **err_msg)
+{
+	struct pipeline_spec *s = NULL;
+	int status = 0;
+
+	/* Check the input arguments. */
+	if (!p || !spec_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Spec file parse. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Pipeline configure. */
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto error;
+	}
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline build error.";
+		goto error;
+	}
+
+	return 0;
+
+error:
+	pipeline_spec_free(s);
 	return status;
 }
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index e1170a33b1..4f3a0b5958 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,3 +206,12 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg);
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 05/17] pipeline: generate the code for pipeline specification structure
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (2 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
                         ` (12 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add support to export the pipeline specification data structure to a C
source code file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 622 +++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h |   5 +
 2 files changed, 627 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 62929a9da6..bf21fe17ba 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2020 Intel Corporation
  */
 #include <stdint.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -2103,6 +2104,627 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
+static const char *
+match_type_string_get(enum rte_swx_table_match_type match_type)
+{
+	switch (match_type) {
+	case RTE_SWX_TABLE_MATCH_WILDCARD: return "RTE_SWX_TABLE_MATCH_WILDCARD";
+	case RTE_SWX_TABLE_MATCH_LPM: return "RTE_SWX_TABLE_MATCH_LPM";
+	case RTE_SWX_TABLE_MATCH_EXACT: return "RTE_SWX_TABLE_MATCH_EXACT";
+	default: return "RTE_SWX_TABLE_MATCH_UNKNOWN";
+	}
+}
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s)
+{
+	uint32_t i;
+
+	/* Check the input arguments. */
+	if (!f || !s)
+		return;
+
+	/* extobj. */
+	fprintf(f, "static struct extobj_spec extobjs[] = {\n");
+
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", extobj_spec->name);
+		fprintf(f, "\t\t.extern_type_name = \"%s\",\n", extobj_spec->extern_type_name);
+		if (extobj_spec->pragma)
+			fprintf(f, "\t\t.pragma = \"%s\",\n", extobj_spec->pragma);
+		else
+			fprintf(f, "\t\t.pragma = NULL,\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* regarray. */
+	fprintf(f, "static struct regarray_spec regarrays[] = {\n");
+
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", regarray_spec->name);
+		fprintf(f, "\t\t.init_val = %" PRIu64 ",\n", regarray_spec->init_val);
+		fprintf(f, "\t\t.size = %u,\n", regarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metarray. */
+	fprintf(f, "static struct metarray_spec metarrays[] = {\n");
+
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", metarray_spec->name);
+		fprintf(f, "\t\t.size = %u,\n", metarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+		uint32_t j;
+
+		fprintf(f, "static struct rte_swx_field_params struct_%s_fields[] = {\n",
+			struct_spec->name);
+
+		for (j = 0; j < struct_spec->n_fields; j++) {
+			struct rte_swx_field_params *field = &struct_spec->fields[j];
+
+			fprintf(f, "\t[%d] = {\n", j);
+			fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+			fprintf(f, "\t\t.n_bits = %u,\n", field->n_bits);
+			fprintf(f, "\t},\n");
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct struct_spec structs[] = {\n");
+
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", struct_spec->name);
+		fprintf(f, "\t\t.fields = struct_%s_fields,\n", struct_spec->name);
+		fprintf(f, "\t\t.n_fields = "
+			"sizeof(struct_%s_fields) / sizeof(struct_%s_fields[0]),\n",
+			struct_spec->name,
+			struct_spec->name);
+		fprintf(f, "\t\t.varbit = %d,\n", struct_spec->varbit);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* header. */
+	fprintf(f, "static struct header_spec headers[] = {\n");
+
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", header_spec->name);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", header_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metadata. */
+	fprintf(f, "static struct metadata_spec metadata[] = {\n");
+
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", metadata_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *action_%s_initial_instructions[] = {\n",
+			action_spec->name);
+
+		for (j = 0; j < action_spec->n_instructions; j++) {
+			const char *instr = action_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct action_spec actions[] = {\n");
+
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", action_spec->name);
+
+		if (action_spec->args_struct_type_name)
+			fprintf(f, "\t\t.args_struct_type_name = \"%s\",\n",
+				action_spec->args_struct_type_name);
+		else
+			fprintf(f, "\t\t.args_struct_type_name = NULL,\n");
+
+		fprintf(f, "\t\t.instructions = action_%s_initial_instructions,\n",
+			action_spec->name);
+		fprintf(f, "\t\t.n_instructions = "
+			"sizeof(action_%s_initial_instructions) / "
+			"sizeof(action_%s_initial_instructions[0]),\n",
+			action_spec->name,
+			action_spec->name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+		uint32_t j;
+
+		/* fields. */
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "static struct rte_swx_match_field_params "
+				"table_%s_fields[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_fields; j++) {
+				struct rte_swx_match_field_params *field =
+					&table_spec->params.fields[j];
+
+				fprintf(f, "\t[%d] = {\n", j);
+				fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+				fprintf(f, "\t\t.match_type = %s,\n",
+					match_type_string_get(field->match_type));
+				fprintf(f, "\t},\n");
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (table_spec->params.action_names && table_spec->params.n_actions) {
+			fprintf(f, "static const char *table_%s_action_names[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				const char *action_name = table_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (table_spec->params.action_is_for_table_entries &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_table_entries[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (table_spec->params.action_is_for_default_entry &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_default_entry[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct table_spec tables[] = {\n");
+
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", table_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.fields = table_%s_fields,\n", table_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(table_%s_fields) / sizeof(table_%s_fields[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.fields = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (table_spec->params.action_names && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = table_%s_action_names,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (table_spec->params.action_is_for_table_entries && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"table_%s_action_is_for_table_entries,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (table_spec->params.action_is_for_default_entry && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"table_%s_action_is_for_default_entry,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = sizeof(table_%s_action_names) / "
+				"sizeof(table_%s_action_names[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = 0,\n");
+
+		if (table_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				table_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (table_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				table_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			table_spec->params.default_action_is_const);
+		fprintf(f, "\t\t},\n");
+
+		if (table_spec->recommended_table_type_name)
+			fprintf(f, "\t\t.recommended_table_type_name = \"%s\",\n",
+				table_spec->recommended_table_type_name);
+		else
+			fprintf(f, "\t\t.recommended_table_type_name = NULL,\n");
+
+		if (table_spec->args)
+			fprintf(f, "\t\t.args = \"%s\",\n", table_spec->args);
+		else
+			fprintf(f, "\t\t.args = NULL,\n");
+
+		fprintf(f, "\t\t.size = %u,\n", table_spec->size);
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+		uint32_t j;
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "static const char *selector_%s_field_names[] = {\n",
+				selector_spec->name);
+
+			for (j = 0; j < selector_spec->params.n_selector_fields; j++) {
+				const char *field_name =
+					selector_spec->params.selector_field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct selector_spec selectors[] = {\n");
+
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+
+		fprintf(f, "\t\t.name = \"%s\",\n", selector_spec->name);
+		fprintf(f, "\t\t.params = {\n");
+
+		if (selector_spec->params.group_id_field_name)
+			fprintf(f, "\t\t\t.group_id_field_name = \"%s\",\n",
+				selector_spec->params.group_id_field_name);
+		else
+			fprintf(f, "\t\t\t.group_id_field_name = NULL,\n");
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "\t\t\t.selector_field_names = selector_%s_field_names,\n",
+				selector_spec->name);
+			fprintf(f, "\t\t\t.n_selector_fields = "
+				"sizeof(selector_%s_field_names) / sizeof(selector_%s_field_names[0]),\n",
+				selector_spec->name,
+				selector_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.selector_field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_selector_fields = 0,\n");
+		}
+
+		if (selector_spec->params.member_id_field_name)
+			fprintf(f, "\t\t\t.member_id_field_name = \"%s\",\n",
+				selector_spec->params.member_id_field_name);
+		else
+			fprintf(f, "\t\t\t.member_id_field_name = NULL,\n");
+
+		fprintf(f, "\t\t\t.n_groups_max = %u,\n", selector_spec->params.n_groups_max);
+
+		fprintf(f, "\t\t\t.n_members_per_group_max = %u,\n",
+			selector_spec->params.n_members_per_group_max);
+
+		fprintf(f, "\t\t},\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+		uint32_t j;
+
+		/* field_names. */
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "static const char *learner_%s_field_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_fields; j++) {
+				const char *field_name = learner_spec->params.field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (learner_spec->params.action_names && learner_spec->params.n_actions) {
+			fprintf(f, "static const char *learner_%s_action_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				const char *action_name = learner_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_table_entries[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_default_entry[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* timeout. */
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "static uint32_t learner_%s_timeout[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->n_timeouts; j++) {
+				uint32_t value = learner_spec->timeout[j];
+
+				fprintf(f, "\t[%d] = %u,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct learner_spec learners[] = {\n");
+
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", learner_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.field_names = learner_%s_field_names,\n",
+				learner_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(learner_%s_field_names) / "
+				"sizeof(learner_%s_field_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = learner_%s_action_names,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"learner_%s_action_is_for_table_entries,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"learner_%s_action_is_for_default_entry,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = "
+				"sizeof(learner_%s_action_names) / sizeof(learner_%s_action_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = NULL,\n");
+
+		if (learner_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				learner_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (learner_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				learner_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			learner_spec->params.default_action_is_const);
+
+		fprintf(f, "\t\t},\n");
+
+		fprintf(f, "\t\t.size = %u,\n", learner_spec->size);
+
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "\t\t.timeout = learner_%s_timeout,\n", learner_spec->name);
+			fprintf(f, "\t\t\t.n_timeouts = "
+				"sizeof(learner_%s_timeout) / sizeof(learner_%s_timeout[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t.timeout = NULL,\n");
+			fprintf(f, "\t\t\t.n_timeouts = 0,\n");
+		}
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *apply%u_initial_instructions[] = {\n", i);
+
+		for (j = 0; j < apply_spec->n_instructions; j++) {
+			const char *instr = apply_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct apply_spec apply[] = {\n");
+
+	for (i = 0; i < s->n_apply; i++) {
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t.instructions = apply%u_initial_instructions,\n", i);
+		fprintf(f, "\t.n_instructions = "
+			"sizeof(apply%u_initial_instructions) / "
+			"sizeof(apply%u_initial_instructions[0]),\n",
+			i,
+			i);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* pipeline. */
+	fprintf(f, "struct pipeline_spec pipeline_spec = {\n");
+	fprintf(f, "\t.extobjs = extobjs,\n");
+	fprintf(f, "\t.structs = structs,\n");
+	fprintf(f, "\t.headers = headers,\n");
+	fprintf(f, "\t.metadata = metadata,\n");
+	fprintf(f, "\t.actions = actions,\n");
+	fprintf(f, "\t.tables = tables,\n");
+	fprintf(f, "\t.selectors = selectors,\n");
+	fprintf(f, "\t.learners = learners,\n");
+	fprintf(f, "\t.regarrays = regarrays,\n");
+	fprintf(f, "\t.metarrays = metarrays,\n");
+	fprintf(f, "\t.apply = apply,\n");
+	fprintf(f, "\t.n_extobjs = sizeof(extobjs) / sizeof(extobjs[0]),\n");
+	fprintf(f, "\t.n_structs = sizeof(structs) / sizeof(structs[0]),\n");
+	fprintf(f, "\t.n_headers = sizeof(headers) / sizeof(headers[0]),\n");
+	fprintf(f, "\t.n_metadata = sizeof(metadata) / sizeof(metadata[0]),\n");
+	fprintf(f, "\t.n_actions = sizeof(actions) / sizeof(actions[0]),\n");
+	fprintf(f, "\t.n_tables = sizeof(tables) / sizeof(tables[0]),\n");
+	fprintf(f, "\t.n_selectors = sizeof(selectors) / sizeof(selectors[0]),\n");
+	fprintf(f, "\t.n_learners = sizeof(learners) / sizeof(learners[0]),\n");
+	fprintf(f, "\t.n_regarrays = sizeof(regarrays) / sizeof(regarrays[0]),\n");
+	fprintf(f, "\t.n_metarrays = sizeof(metarrays) / sizeof(metarrays[0]),\n");
+	fprintf(f, "\t.n_apply = sizeof(apply) / sizeof(apply[0]),\n");
+	fprintf(f, "};\n");
+}
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 4f3a0b5958..707b99ba09 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,6 +206,11 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s);
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 06/17] pipeline: add support for pipeline I/O specification
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (3 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
                         ` (11 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add specification data structure and API for the pipeline I/O ports
and related pipeline configuration such as packet mirroring.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 852 +++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h |  58 ++
 2 files changed, 910 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index bf21fe17ba..aea69b500b 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -9,6 +9,12 @@
 #include <errno.h>
 
 #include <rte_common.h>
+#include <rte_mempool.h>
+
+#include <rte_swx_port_ethdev.h>
+#include <rte_swx_port_ring.h>
+#include <rte_swx_port_source_sink.h>
+#include <rte_swx_port_fd.h>
 
 #include "rte_swx_pipeline_spec.h"
 
@@ -3566,3 +3572,849 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	pipeline_spec_free(s);
 	return status;
 }
+
+static void
+port_in_params_free(void *params, const char *port_type)
+{
+	uintptr_t dev_name;
+
+	if (!params || !port_type)
+		return;
+
+	if (!strcmp(port_type, "ethdev")) {
+		struct rte_swx_port_ethdev_reader_params *p = params;
+
+		dev_name = (uintptr_t)p->dev_name;
+	} else if (!strcmp(port_type, "ring")) {
+		struct rte_swx_port_ring_reader_params *p = params;
+
+		dev_name = (uintptr_t)p->name;
+	} else if (!strcmp(port_type, "source")) {
+		struct rte_swx_port_source_params *p = params;
+
+		dev_name = (uintptr_t)p->file_name;
+	} else
+		dev_name = (uintptr_t)NULL;
+
+	free((void *)dev_name);
+	free(params);
+}
+
+static void
+port_out_params_free(void *params, const char *port_type)
+{
+	uintptr_t dev_name;
+
+	if (!params || !port_type)
+		return;
+
+	if (!strcmp(port_type, "ethdev")) {
+		struct rte_swx_port_ethdev_writer_params *p = params;
+
+		dev_name = (uintptr_t)p->dev_name;
+	} else if (!strcmp(port_type, "ring")) {
+		struct rte_swx_port_ring_writer_params *p = params;
+
+		dev_name = (uintptr_t)p->name;
+	} else if (!strcmp(port_type, "sink")) {
+		struct rte_swx_port_sink_params *p = params;
+
+		dev_name = (uintptr_t)p->file_name;
+	} else
+		dev_name = (uintptr_t)NULL;
+
+	free((void *)dev_name);
+	free(params);
+}
+
+void
+pipeline_iospec_free(struct pipeline_iospec *s)
+{
+	uint32_t i;
+
+	if (!s)
+		return;
+
+	/* Input ports. */
+	for (i = 0; i < s->n_ports_in; i++) {
+		uintptr_t name = (uintptr_t)s->port_in_type[i];
+
+		port_in_params_free(s->port_in_params[i], s->port_in_type[i]);
+		free((void *)name);
+	}
+
+	free(s->port_in_type);
+	free(s->port_in_params);
+
+	/* Output ports. */
+	for (i = 0; i < s->n_ports_out; i++) {
+		uintptr_t name = (uintptr_t)s->port_out_type[i];
+
+		port_out_params_free(s->port_out_params[i], s->port_out_type[i]);
+		free((void *)name);
+	}
+
+	free(s->port_out_type);
+	free(s->port_out_params);
+
+	free(s);
+}
+
+static int
+mirroring_parse(struct rte_swx_pipeline_mirroring_params *p,
+		char **tokens,
+		uint32_t n_tokens,
+		const char **err_msg)
+{
+	char *token;
+
+	if ((n_tokens != 4) || strcmp(tokens[0], "slots") || strcmp(tokens[2], "sessions")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return -EINVAL;
+	}
+
+	/* <n_slots>. */
+	token = tokens[1];
+	p->n_slots = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_slots> parameter.";
+		return -EINVAL;
+	}
+
+	/* <n_sessions>. */
+	token = tokens[3];
+	p->n_sessions = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_sessions> parameter.";
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+port_in_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ethdev_reader_params *p = NULL;
+	char *token, *dev_name = NULL;
+	uint32_t queue_id, burst_size;
+
+	if ((n_tokens != 5) || strcmp(tokens[1], "rxq") || strcmp(tokens[3], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <queue_id>. */
+	token = tokens[2];
+	queue_id = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <queue_id> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[4];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	dev_name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ethdev_reader_params));
+	if (!dev_name || !p) {
+		free(dev_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->dev_name = dev_name;
+	p->queue_id = queue_id;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_in_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ring_reader_params *p = NULL;
+	char *token, *name = NULL;
+	uint32_t burst_size;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ring_reader_params));
+	if (!name || !p) {
+		free(name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->name = name;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_in_source_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_source_params *p = NULL;
+	struct rte_mempool *pool = NULL;
+	char *token, *file_name = NULL;
+	uint32_t n_loops, n_pkts_max;
+
+	if ((n_tokens != 8) ||
+	    strcmp(tokens[0], "mempool") ||
+	    strcmp(tokens[2], "file") ||
+	    strcmp(tokens[4], "loop") ||
+	    strcmp(tokens[6], "packets")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <mempool_name>. */
+	pool = rte_mempool_lookup(tokens[1]);
+	if (!pool) {
+		if (err_msg)
+			*err_msg = "Invalid <mempool_name> parameter.";
+		return NULL;
+	}
+
+	/* <n_loops>. */
+	token = tokens[5];
+	n_loops = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_loops> parameter.";
+		return NULL;
+	}
+
+	/* <n_pkts_max>. */
+	token = tokens[7];
+	n_pkts_max = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_pkts_max> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	file_name = strdup(tokens[3]);
+	p = malloc(sizeof(struct rte_swx_port_source_params));
+	if (!file_name || !p) {
+		free(file_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->pool = pool;
+	p->file_name = file_name;
+	p->n_loops = n_loops;
+	p->n_pkts_max = n_pkts_max;
+
+	return p;
+}
+
+static void *
+port_in_fd_parse(char **tokens,
+		 uint32_t n_tokens,
+		 const char **err_msg)
+{
+	struct rte_swx_port_fd_reader_params *p = NULL;
+	struct rte_mempool *mempool = NULL;
+	char *token;
+	uint32_t mtu, burst_size;
+	int fd;
+
+	if ((n_tokens != 7) ||
+	    strcmp(tokens[1], "mtu") ||
+	    strcmp(tokens[3], "mempool") ||
+	    strcmp(tokens[5], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <file_descriptor>. */
+	token = tokens[0];
+	fd = strtol(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <file_descriptor> parameter.";
+		return NULL;
+	}
+
+	/* <mtu>. */
+	token = tokens[2];
+	mtu = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <mtu> parameter.";
+		return NULL;
+	}
+
+	/* <mempool_name>. */
+	mempool = rte_mempool_lookup(tokens[4]);
+	if (!mempool) {
+		if (err_msg)
+			*err_msg = "Invalid <mempool_name> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[6];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	p = malloc(sizeof(struct rte_swx_port_fd_reader_params));
+	if (!p) {
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->fd = fd;
+	p->mtu = mtu;
+	p->mempool = mempool;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ethdev_writer_params *p = NULL;
+	char *token, *dev_name = NULL;
+	uint32_t queue_id, burst_size;
+
+	if ((n_tokens != 5) || strcmp(tokens[1], "txq") || strcmp(tokens[3], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <queue_id>. */
+	token = tokens[2];
+	queue_id = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <queue_id> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[4];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	dev_name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ethdev_writer_params));
+	if (!dev_name || !p) {
+		free(dev_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->dev_name = dev_name;
+	p->queue_id = queue_id;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ring_writer_params *p = NULL;
+	char *token, *name = NULL;
+	uint32_t burst_size;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
+	if (!name || !p) {
+		free(name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->name = name;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_sink_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_sink_params *p = NULL;
+	char *file_name = NULL;
+	int file_name_valid = 0;
+
+	if ((n_tokens != 2) || strcmp(tokens[0], "file")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	if (strcmp(tokens[1], "none")) {
+		file_name_valid = 1;
+		file_name = strdup(tokens[1]);
+	}
+
+	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
+	if ((file_name_valid && !file_name) || !p) {
+		free(file_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->file_name = file_name;
+
+	return p;
+}
+
+static void *
+port_out_fd_parse(char **tokens,
+		  uint32_t n_tokens,
+		  const char **err_msg)
+{
+	struct rte_swx_port_fd_writer_params *p = NULL;
+	char *token;
+	uint32_t burst_size;
+	int fd;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <file_descriptor>. */
+	token = tokens[0];
+	fd = strtol(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <file_descriptor> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	p = malloc(sizeof(struct rte_swx_port_fd_writer_params));
+	if (!p) {
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->fd = fd;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+struct pipeline_iospec *
+pipeline_iospec_parse(FILE *spec,
+		      uint32_t *err_line,
+		      const char **err_msg)
+{
+	struct pipeline_iospec *s = NULL;
+	uint32_t n_lines = 0;
+
+	/* Check the input arguments. */
+	if (!spec) {
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		goto error;
+	}
+
+	/* Memory allocation. */
+	s = calloc(sizeof(struct pipeline_iospec), 1);
+	if (!s) {
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		goto error;
+	}
+
+	/* Initialize with the defaut values. */
+	s->mirroring_params.n_slots = RTE_SWX_PACKET_MIRRORING_SLOTS_DEFAULT;
+	s->mirroring_params.n_sessions = RTE_SWX_PACKET_MIRRORING_SESSIONS_DEFAULT;
+
+	for (n_lines = 1; ; n_lines++) {
+		char line[MAX_LINE_LENGTH];
+		char *tokens[MAX_TOKENS], *ptr = line;
+		uint32_t n_tokens = 0;
+
+		/* Read next line. */
+		if (!fgets(line, sizeof(line), spec))
+			break;
+
+		/* Parse the line into tokens. */
+		for ( ; ; ) {
+			char *token;
+
+			/* Get token. */
+			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
+			if (!token)
+				break;
+
+			/* Handle comments. */
+			if ((token[0] == '#') ||
+			    (token[0] == ';') ||
+			    ((token[0] == '/') && (token[1] == '/'))) {
+				break;
+			}
+
+			/* Handle excessively long lines. */
+			if (n_tokens >= RTE_DIM(tokens)) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Too many tokens.";
+				goto error;
+			}
+
+			/* Handle excessively long tokens. */
+			if (strnlen(token, RTE_SWX_NAME_SIZE) >=
+			    RTE_SWX_NAME_SIZE) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Token too big.";
+				goto error;
+			}
+
+			/* Save token. */
+			tokens[n_tokens] = token;
+			n_tokens++;
+		}
+
+		/* Handle empty lines. */
+		if (!n_tokens)
+			continue;
+
+		/* mirroring. */
+		if ((n_tokens >= 1) && !strcmp(tokens[0], "mirroring")) {
+			int status = 0;
+
+			status = mirroring_parse(&s->mirroring_params,
+						 &tokens[1],
+						 n_tokens - 1,
+						 err_msg);
+			if (status) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			continue;
+		}
+
+		/* port in. */
+		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "in")) {
+			char *token = tokens[2];
+			uint32_t *new_id = NULL;
+			const char **new_type = NULL, *port_type = NULL;
+			void **new_params = NULL, *p = NULL;
+			uint32_t port_id;
+
+			/* <port_id>. */
+			port_id = strtoul(token, &token, 0);
+			if (token[0]) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Invalid port ID.";
+				goto error;
+			}
+
+			/* <port_type>. */
+			if (!strcmp(tokens[3], "ethdev"))
+				p = port_in_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "ring"))
+				p = port_in_ring_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "source"))
+				p = port_in_source_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "fd"))
+				p = port_in_fd_parse(&tokens[4], n_tokens - 4, err_msg);
+			else {
+				p = NULL;
+				if (err_msg)
+					*err_msg = "Invalid port type.";
+			}
+
+			if (!p) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			/* New port. */
+			port_type = strdup(tokens[3]);
+			new_id = realloc(s->port_in_id,
+					 (s->n_ports_in + 1) * sizeof(uint32_t));
+			new_type = realloc(s->port_in_type,
+					   (s->n_ports_in + 1) * sizeof(char *));
+			new_params = realloc(s->port_in_params,
+					     (s->n_ports_in + 1) * sizeof(void *));
+			if (!port_type || !new_id || !new_type || !new_params) {
+				uintptr_t pt = (uintptr_t)port_type;
+
+				port_in_params_free(p, tokens[3]);
+				free((void *)pt);
+				free(new_id);
+				free(new_type);
+				free(new_params);
+
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Memory allocation failed.";
+				goto error;
+			}
+
+			s->port_in_id = new_id;
+			s->port_in_type = new_type;
+			s->port_in_params = new_params;
+
+			s->port_in_id[s->n_ports_in] = port_id;
+			s->port_in_type[s->n_ports_in] = port_type;
+			s->port_in_params[s->n_ports_in] = p;
+			s->n_ports_in++;
+
+			continue;
+		}
+
+		/* port out. */
+		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "out")) {
+			char *token = tokens[2];
+			uint32_t *new_id = NULL;
+			const char **new_type = NULL, *port_type = NULL;
+			void **new_params = NULL, *p = NULL;
+			uint32_t port_id;
+
+			/* <port_id>. */
+			port_id = strtoul(token, &token, 0);
+			if (token[0]) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Invalid port ID.";
+				goto error;
+			}
+
+			/* <port_type>. */
+			if (!strcmp(tokens[3], "ethdev"))
+				p = port_out_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "ring"))
+				p = port_out_ring_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "sink"))
+				p = port_out_sink_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "fd"))
+				p = port_out_fd_parse(&tokens[4], n_tokens - 4, err_msg);
+			else {
+				p = NULL;
+				if (err_msg)
+					*err_msg = "Invalid port type.";
+			}
+
+			if (!p) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			/* New port. */
+			port_type = strdup(tokens[3]);
+			new_id = realloc(s->port_out_id,
+					 (s->n_ports_out + 1) * sizeof(uint32_t));
+			new_type = realloc(s->port_out_type,
+					   (s->n_ports_out + 1) * sizeof(char *));
+			new_params = realloc(s->port_out_params,
+					     (s->n_ports_out + 1) * sizeof(void *));
+			if (!port_type || !new_id || !new_type || !new_params) {
+				uintptr_t pt = (uintptr_t)port_type;
+
+				port_out_params_free(p, tokens[3]);
+				free((void *)pt);
+				free(new_id);
+				free(new_type);
+				free(new_params);
+
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Memory allocation failed.";
+				goto error;
+			}
+
+			s->port_out_id = new_id;
+			s->port_out_type = new_type;
+			s->port_out_params = new_params;
+
+			s->port_out_id[s->n_ports_out] = port_id;
+			s->port_out_type[s->n_ports_out] = port_type;
+			s->port_out_params[s->n_ports_out] = p;
+			s->n_ports_out++;
+
+			continue;
+		}
+
+		/* Anything else. */
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Unknown I/O statement.";
+		goto error;
+	}
+
+	return s;
+
+error:
+	pipeline_iospec_free(s);
+
+	return NULL;
+}
+
+int
+pipeline_iospec_configure(struct rte_swx_pipeline *p,
+			  struct pipeline_iospec *s,
+			  const char **err_msg)
+{
+	uint32_t i;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!p || !s) {
+		if (err_msg)
+			*err_msg = "Invalid input argument";
+		return -EINVAL;
+	}
+
+	/* Mirroring. */
+	status = rte_swx_pipeline_mirroring_config(p, &s->mirroring_params);
+	if (status) {
+		if (err_msg)
+			*err_msg = "Pipeline mirroring configuration error.";
+		return status;
+	}
+
+	/* Input ports. */
+	for (i = 0; i < s->n_ports_in; i++) {
+		status = rte_swx_pipeline_port_in_config(p,
+							 i,
+							 s->port_in_type[i],
+							 s->port_in_params[i]);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline input port configuration error.";
+			return status;
+		}
+	}
+
+	/* Output ports. */
+	for (i = 0; i < s->n_ports_out; i++) {
+		status = rte_swx_pipeline_port_out_config(p,
+							  i,
+							  s->port_out_type[i],
+							  s->port_out_params[i]);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline output port configuration error.";
+			return status;
+		}
+	}
+
+	return 0;
+}
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 707b99ba09..62ac4ecfc4 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -1,6 +1,13 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright(c) 2022 Intel Corporation
  */
+#ifndef __INCLUDE_RTE_SWX_PIPELINE_SPEC_H__
+#define __INCLUDE_RTE_SWX_PIPELINE_SPEC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <stdint.h>
 #include <stdio.h>
 
@@ -204,6 +211,38 @@ struct pipeline_spec {
 	uint32_t n_apply;
 };
 
+/*
+ * Mirroring:
+ *      mirroring slots <n_slots> sessions <n_sessions>
+ *
+ * Input ports:
+ *      port in <port_id> ethdev <ethdev_name> rxq <queue_id> bsz <burst_size>
+ *      port in <port_id> ring <ring_name> bsz <burst_size>
+ *      port in <port_id> source mempool <mempool_name> file <file_name> loop <n_loops>
+ *                               packets <n_pkts_max>
+ *      port in <port_id> fd <file_descriptor> mtu <mtu> mempool <mempool_name> bsz <burst_size>
+ *
+ * Output ports:
+ *      port out <port_id> ethdev <ethdev_name> txq <queue_id> bsz <burst_size>
+ *      port out <port_id> ring <ring_name> bsz <burst_size>
+ *      port out <port_id> sink file <file_name> | none
+ *      port out <port_id> fd <file_descriptor> bsz <burst_size>
+ */
+struct pipeline_iospec {
+	struct rte_swx_pipeline_mirroring_params mirroring_params;
+
+	uint32_t *port_in_id;
+	const char **port_in_type;
+	void **port_in_params;
+
+	uint32_t *port_out_id;
+	const char **port_out_type;
+	void **port_out_params;
+
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+};
+
 void
 pipeline_spec_free(struct pipeline_spec *s);
 
@@ -220,3 +259,22 @@ int
 pipeline_spec_configure(struct rte_swx_pipeline *p,
 			struct pipeline_spec *s,
 			const char **err_msg);
+
+void
+pipeline_iospec_free(struct pipeline_iospec *s);
+
+struct pipeline_iospec *
+pipeline_iospec_parse(FILE *spec,
+		      uint32_t *err_line,
+		      const char **err_msg);
+
+int
+pipeline_iospec_configure(struct rte_swx_pipeline *p,
+			  struct pipeline_iospec *s,
+			  const char **err_msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 07/17] pipeline: add API for pipeline code generation
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (4 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
                         ` (10 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the C code generation for the pipeline was hidden under
the hood; now, we make this an explicit API operation. Besides the
functions for the pipeline actions and the pipeline instructions,
the generated C source code now includes the pipeline specification
structure required for the pipeline configuration operations.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline.c | 94 +++++++++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline.h | 25 +++++++++
 lib/pipeline/version.map        |  1 +
 3 files changed, 120 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index c8ccded4f8..dd5f7107fa 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -20,6 +20,7 @@
 #include <rte_swx_table_wm.h>
 
 #include "rte_swx_pipeline_internal.h"
+#include "rte_swx_pipeline_spec.h"
 
 #define CHECK(condition, err_code)                                             \
 do {                                                                           \
@@ -13581,3 +13582,96 @@ pipeline_compile(struct rte_swx_pipeline *p)
 
 	return status;
 }
+
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg)
+
+{
+	struct rte_swx_pipeline *p = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!spec_file || !code_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	status = rte_swx_pipeline_config(&p, NULL, 0);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline configuration error.";
+		goto free;
+	}
+
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto free;
+	}
+
+	/*
+	 * Pipeline code generation.
+	 */
+
+	/* Instruction Group List (IGL) computation: the pipeline configuration must be done first,
+	 * but there is no need for the pipeline build to be done as well.
+	 */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
+		goto free;
+	}
+
+	/* Header file inclusion. */
+	fprintf(code_file, "#include \"rte_swx_pipeline_internal.h\"\n");
+	fprintf(code_file, "#include \"rte_swx_pipeline_spec.h\"\n\n");
+
+	/* Code generation for the pipeline specification. */
+	pipeline_spec_codegen(code_file, s);
+	fprintf(code_file, "\n");
+
+	/* Code generation for the action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		fprintf(code_file, "/**\n * Action %s\n */\n\n", a->name);
+
+		action_data_codegen(a, code_file);
+		fprintf(code_file, "\n");
+
+		action_instr_codegen(a, code_file);
+		fprintf(code_file, "\n");
+	}
+
+	/* Code generation for the pipeline instructions. */
+	instruction_group_list_codegen(igl, p, code_file);
+
+free:
+	instruction_group_list_free(igl);
+	rte_swx_pipeline_free(p);
+	pipeline_spec_free(s);
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index ef50a0fa70..724607b87c 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -957,6 +957,31 @@ __rte_experimental
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p);
 
+/**
+ * Pipeline C code generate based on input specification file
+ *
+ * @param[in] spec_file
+ *   Pipeline specification file (.spec) provided as input.
+ * @param[in] code_file
+ *   Pipeline C language file (.c) to be generated.
+ * @param[out] err_line
+ *   In case of error and non-NULL, the line number within the *spec* file where
+ *   the error occurred. The first line number in the file is 1.
+ * @param[out] err_msg
+ *   In case of error and non-NULL, the error message.
+ * @return
+ *   0 on success or the following error codes otherwise:
+ *   -EINVAL: Invalid argument;
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -EEXIST: Resource with the same name already exists.
+ */
+__rte_experimental
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg);
+
 /**
  * Pipeline build from specification file
  *
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 50029aadcf..8d95005a5b 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -148,5 +148,6 @@ EXPERIMENTAL {
 
 	#added in 22.11
 	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_codegen;
 	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 08/17] pipeline: add API for shared library-based pipeline build
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (5 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
                         ` (9 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the pipeline build operation was done based on the
specification file (typically produced by the P4 compiler), then the C
code with optimized functions for the pipeline actions and
instructions was generated, built into a shared object library, loaded
and installed into the pipeline in a completely hardcoded and
non-customizable way.

Now, this process is split into three explicit stages:
i) code generation (specification file -> C file);
ii) code build (C file -> shared object library);
iii) code installation (library load into the pipeline).

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c              |  85 ++++---
 lib/pipeline/rte_swx_pipeline.c      | 319 +++++++++++----------------
 lib/pipeline/rte_swx_pipeline.h      |  38 ++--
 lib/pipeline/rte_swx_pipeline_spec.c |  51 -----
 lib/pipeline/version.map             |   2 +-
 5 files changed, 208 insertions(+), 287 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index ad553f19ab..f0285675b3 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -984,55 +984,88 @@ cmd_pipeline_port_out(char **tokens,
 }
 
 static const char cmd_pipeline_build_help[] =
-"pipeline <pipeline_name> build <spec_file>\n";
+"pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
 static void
 cmd_pipeline_build(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p = NULL;
-	FILE *spec = NULL;
-	uint32_t err_line;
-	const char *err_msg;
-	int status;
+	struct rte_swx_pipeline *p = NULL;
+	struct rte_swx_ctl_pipeline *ctl = NULL;
+	char *pipeline_name, *lib_file_name, *iospec_file_name;
+	FILE *iospec_file = NULL;
+	uint32_t numa_node = 0;
+	int status = 0;
 
-	if (n_tokens != 4) {
+	/* Parsing. */
+	if (n_tokens != 9) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "build")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "build");
 		return;
 	}
 
-	spec = fopen(tokens[3], "r");
-	if (!spec) {
-		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
+	if (strcmp(tokens[3], "lib")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "lib");
 		return;
 	}
 
-	status = rte_swx_pipeline_build_from_spec(p->p,
-		spec,
-		&err_line,
-		&err_msg);
-	fclose(spec);
-	if (status) {
-		snprintf(out, out_size, "Error %d at line %u: %s\n.",
-			status, err_line, err_msg);
+	lib_file_name = tokens[4];
+
+	if (strcmp(tokens[5], "io")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "io");
 		return;
 	}
 
-	p->ctl = rte_swx_ctl_pipeline_create(p->p);
-	if (!p->ctl) {
-		snprintf(out, out_size, "Pipeline control create failed.");
-		rte_swx_pipeline_free(p->p);
+	iospec_file_name = tokens[6];
+
+	if (strcmp(tokens[7], "numa")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa");
 		return;
 	}
+
+	if (parser_read_uint32(&numa_node, tokens[8])) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "numa_node");
+		return;
+	}
+
+	/* I/O spec file open. */
+	iospec_file = fopen(iospec_file_name, "r");
+	if (!iospec_file) {
+		snprintf(out, out_size, "Cannot open file \"%s\".\n", iospec_file_name);
+		return;
+	}
+
+	status = rte_swx_pipeline_build_from_lib(&p,
+						 pipeline_name,
+						 lib_file_name,
+						 iospec_file,
+						 (int)numa_node);
+	if (status) {
+		snprintf(out, out_size, "Pipeline build failed (%d).", status);
+		goto free;
+	}
+
+	ctl = rte_swx_ctl_pipeline_create(p);
+	if (!ctl) {
+		snprintf(out, out_size, "Pipeline control create failed.");
+		goto free;
+	}
+
+free:
+	if (status)
+		rte_swx_pipeline_free(p);
+
+	if (iospec_file)
+		fclose(iospec_file);
 }
 
 static void
diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index dd5f7107fa..12e156b00b 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -9911,9 +9911,6 @@ rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p,
 	return 0;
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p);
-
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 {
@@ -10003,8 +10000,6 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 
 	p->build_done = 1;
 
-	pipeline_compile(p);
-
 	return 0;
 
 error:
@@ -13327,160 +13322,6 @@ instruction_group_list_custom_instructions_count(struct instruction_group_list *
 	return n_custom_instr;
 }
 
-static int
-pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	FILE *f = NULL;
-
-	/* Create the .c file. */
-	f = fopen("/tmp/pipeline.c", "w");
-	if (!f)
-		return -EIO;
-
-	/* Include the .h file. */
-	fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n");
-
-	/* Add the code for each action. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		fprintf(f, "/**\n * Action %s\n */\n\n", a->name);
-
-		action_data_codegen(a, f);
-
-		fprintf(f, "\n");
-
-		action_instr_codegen(a, f);
-
-		fprintf(f, "\n");
-	}
-
-	/* Add the pipeline code. */
-	instruction_group_list_codegen(igl, p, f);
-
-	/* Close the .c file. */
-	fclose(f);
-
-	return 0;
-}
-
-#ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE
-#define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096
-#endif
-
-static int
-pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	struct instruction_group *g;
-	char *dir_in, *buffer = NULL;
-	const char *dir_out;
-	int status = 0;
-
-	/* Get the environment variables. */
-	dir_in = getenv("RTE_INSTALL_DIR");
-	if (!dir_in) {
-		status = -EINVAL;
-		goto free;
-	}
-
-	dir_out = "/tmp";
-
-	/* Memory allocation for the command buffer. */
-	buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE);
-	if (!buffer) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c "
-		 "-I %s/lib/pipeline "
-		 "-I %s/lib/eal/include "
-		 "-I %s/lib/eal/x86/include "
-		 "-I %s/lib/eal/include/generic "
-		 "-I %s/lib/meter "
-		 "-I %s/lib/port "
-		 "-I %s/lib/table "
-		 "-I %s/lib/pipeline "
-		 "-I %s/config "
-		 "-I %s/build "
-		 "-I %s/lib/eal/linux/include "
-		 ">%s/pipeline.log 2>&1 "
-		 "&& "
-		 "gcc -shared %s/pipeline.o -o %s/libpipeline.so "
-		 ">>%s/pipeline.log 2>&1",
-		 dir_out,
-		 dir_out,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_out,
-		 dir_out,
-		 dir_out,
-		 dir_out);
-
-	/* Build the shared object library. */
-	status = system(buffer);
-	if (status)
-		goto free;
-
-	/* Open library. */
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "%s/libpipeline.so",
-		 dir_out);
-
-	p->lib = dlopen(buffer, RTLD_LAZY);
-	if (!p->lib) {
-		status = -EIO;
-		goto free;
-	}
-
-	/* Get the action function symbols. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name);
-
-		p->action_funcs[a->id] = dlsym(p->lib, buffer);
-		if (!p->action_funcs[a->id]) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-	/* Get the pipeline function symbols. */
-	TAILQ_FOREACH(g, igl, node) {
-		if (g->first_instr_id == g->last_instr_id)
-			continue;
-
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id);
-
-		g->func = dlsym(p->lib, buffer);
-		if (!g->func) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-free:
-	if (status && p->lib) {
-		dlclose(p->lib);
-		p->lib = NULL;
-	}
-
-	free(buffer);
-
-	return status;
-}
-
 static int
 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused,
 		      struct instruction_group_list *igl)
@@ -13548,41 +13389,6 @@ pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
 	instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions);
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p)
-{
-	struct instruction_group_list *igl = NULL;
-	int status = 0;
-
-	igl = instruction_group_list_create(p);
-	if (!igl) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	/* Code generation. */
-	status = pipeline_codegen(p, igl);
-	if (status)
-		goto free;
-
-	/* Build and load the shared object library. */
-	status = pipeline_libload(p, igl);
-	if (status)
-		goto free;
-
-	/* Adjust instructions. */
-	status = pipeline_adjust_check(p, igl);
-	if (status)
-		goto free;
-
-	pipeline_adjust(p, igl);
-
-free:
-	instruction_group_list_free(igl);
-
-	return status;
-}
-
 int
 rte_swx_pipeline_codegen(FILE *spec_file,
 			 FILE *code_file,
@@ -13675,3 +13481,128 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 
 	return status;
 }
+
+int
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline **pipeline,
+				const char *name,
+				const char *lib_file_name,
+				FILE *iospec_file,
+				int numa_node)
+{
+	struct rte_swx_pipeline *p = NULL;
+	void *lib = NULL;
+	struct pipeline_iospec *sio = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	struct instruction_group *g;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!pipeline ||
+	    !name ||
+	    !name[0] ||
+	    !lib_file_name ||
+	    !lib_file_name[0] ||
+	    !iospec_file) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Open the library. */
+	lib = dlopen(lib_file_name, RTLD_LAZY);
+	if (!lib) {
+		status = -EIO;
+		goto free;
+	}
+
+	/* Get the pipeline specification structures. */
+	s = dlsym(lib, "pipeline_spec");
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	sio = pipeline_iospec_parse(iospec_file, NULL, NULL);
+	if (!sio) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration based on the specification structures. */
+	status = rte_swx_pipeline_config(&p, name, numa_node);
+	if (status)
+		goto free;
+
+	status = pipeline_iospec_configure(p, sio, NULL);
+	if (status)
+		goto free;
+
+	status = pipeline_spec_configure(p, s, NULL);
+	if (status)
+		goto free;
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status)
+		goto free;
+
+	/* Action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		snprintf(name, sizeof(name), "action_%s_run", a->name);
+
+		p->action_funcs[a->id] = dlsym(lib, name);
+		if (!p->action_funcs[a->id]) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	/* Pipeline instructions. */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		status = -ENOMEM;
+		goto free;
+	}
+
+	TAILQ_FOREACH(g, igl, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		if (g->first_instr_id == g->last_instr_id)
+			continue;
+
+		snprintf(name, sizeof(name), "pipeline_func_%u", g->group_id);
+
+		g->func = dlsym(lib, name);
+		if (!g->func) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	status = pipeline_adjust_check(p, igl);
+	if (status)
+		goto free;
+
+	pipeline_adjust(p, igl);
+
+	p->lib = lib;
+
+	*pipeline = p;
+
+free:
+	instruction_group_list_free(igl);
+
+	pipeline_iospec_free(sio);
+
+	if (status) {
+		rte_swx_pipeline_free(p);
+
+		if (lib)
+			dlclose(lib);
+	}
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index 724607b87c..9c629d4118 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -983,30 +983,38 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 			 const char **err_msg);
 
 /**
- * Pipeline build from specification file
+ * Pipeline build from shared object library
  *
- * @param[in] p
- *   Pipeline handle.
- * @param[in] spec
- *   Pipeline specification file.
- * @param[out] err_line
- *   In case of error and non-NULL, the line number within the *spec* file where
- *   the error occurred. The first line number in the file is 1.
- * @param[out] err_msg
- *   In case of error and non-NULL, the error message.
+ * The shared object library must be built from the C language source code file
+ * previously generated by the rte_swx_pipeline_codegen() API function.
+ *
+ * The pipeline I/O specification file defines the I/O ports of the pipeline.
+ *
+ * @param[out] p
+ *   Pipeline handle. Must point to valid memory. Contains valid pipeline handle
+ *   when the function returns successfully.
+ * @param[in] name
+ *   Pipeline unique name.
+ * @param[in] lib_file_name
+ *   Shared object library file name.
+ * @param[in] iospec_file
+ *   Pipeline I/O specification file.
+ * @param[in] numa_node
+ *   Non-Uniform Memory Access (NUMA) node.
  * @return
  *   0 on success or the following error codes otherwise:
  *   -EINVAL: Invalid argument;
  *   -ENOMEM: Not enough space/cannot allocate memory;
- *   -EEXIST: Resource with the same name already exists;
+ *   -EEXIST: Pipeline with this name already exists;
  *   -ENODEV: Extern object or table creation error.
  */
 __rte_experimental
 int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg);
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline **p,
+				const char *name,
+				const char *lib_file_name,
+				FILE *iospec_file,
+				int numa_node);
 
 /**
  * Pipeline run
diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index aea69b500b..63c919d16e 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -3522,57 +3522,6 @@ pipeline_spec_configure(struct rte_swx_pipeline *p,
 	return 0;
 }
 
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec_file,
-				 uint32_t *err_line,
-				 const char **err_msg)
-{
-	struct pipeline_spec *s = NULL;
-	int status = 0;
-
-	/* Check the input arguments. */
-	if (!p || !spec_file) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Invalid input argument.";
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Spec file parse. */
-	s = pipeline_spec_parse(spec_file, err_line, err_msg);
-	if (!s) {
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Pipeline configure. */
-	status = pipeline_spec_configure(p, s, err_msg);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		goto error;
-	}
-
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
-
-error:
-	pipeline_spec_free(s);
-	return status;
-}
-
 static void
 port_in_params_free(void *params, const char *port_type)
 {
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 8d95005a5b..16806e6802 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -82,7 +82,6 @@ EXPERIMENTAL {
 	rte_swx_ctl_table_ops_get;
 	rte_swx_pipeline_action_config;
 	rte_swx_pipeline_build;
-	rte_swx_pipeline_build_from_spec;
 	rte_swx_pipeline_config;
 	rte_swx_pipeline_extern_func_register;
 	rte_swx_pipeline_extern_object_config;
@@ -148,6 +147,7 @@ EXPERIMENTAL {
 
 	#added in 22.11
 	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_build_from_lib;
 	rte_swx_pipeline_codegen;
 	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 09/17] examples/pipeline: add CLI command for pipeline code generation
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (6 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
                         ` (8 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the pipeline code generation operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 61 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index f0285675b3..2b38977be1 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -983,6 +983,53 @@ cmd_pipeline_port_out(char **tokens,
 	}
 }
 
+static const char cmd_pipeline_codegen_help[] =
+"pipeline codegen <spec_file> <code_file>\n";
+
+static void
+cmd_pipeline_codegen(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	FILE *spec_file = NULL;
+	FILE *code_file = NULL;
+	uint32_t err_line;
+	const char *err_msg;
+	int status;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	spec_file = fopen(tokens[2], "r");
+	if (!spec_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[2]);
+		return;
+	}
+
+	code_file = fopen(tokens[3], "w");
+	if (!code_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
+		return;
+	}
+
+	status = rte_swx_pipeline_codegen(spec_file,
+					  code_file,
+					  &err_line,
+					  &err_msg);
+
+	fclose(spec_file);
+	fclose(code_file);
+
+	if (status) {
+		snprintf(out, out_size, "Error %d at line %u: %s\n.",
+			status, err_line, err_msg);
+		return;
+	}
+}
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
@@ -3009,6 +3056,7 @@ cmd_help(char **tokens,
 			"\tpipeline create\n"
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
+			"\tpipeline codegen\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3078,6 +3126,12 @@ cmd_help(char **tokens,
 		}
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3356,6 +3410,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "codegen") == 0)) {
+			cmd_pipeline_codegen(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 10/17] examples/pipeline: add CLI command for shared library build
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (7 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
                         ` (7 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the shared object library build operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 157 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 153 insertions(+), 4 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 2b38977be1..28cf8d4178 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -6,6 +6,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_ethdev.h>
@@ -25,6 +26,10 @@
 #define CMD_MAX_TOKENS     256
 #endif
 
+#ifndef MAX_LINE_SIZE
+#define MAX_LINE_SIZE 2048
+#endif
+
 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
@@ -1030,6 +1035,140 @@ cmd_pipeline_codegen(char **tokens,
 		return;
 	}
 }
+
+static const char cmd_pipeline_libbuild_help[] =
+"pipeline libbuild <code_file> <lib_file>\n";
+
+static void
+cmd_pipeline_libbuild(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	char *code_file, *lib_file, *obj_file = NULL, *log_file = NULL;
+	char *install_dir, *cwd = NULL, *buffer = NULL;
+	size_t length;
+	int status = 0;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		goto free;
+	}
+
+	install_dir = getenv("RTE_INSTALL_DIR");
+	if (!install_dir) {
+		cwd = malloc(MAX_LINE_SIZE);
+		if (!cwd) {
+			snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+			goto free;
+		}
+
+		install_dir = getcwd(cwd, MAX_LINE_SIZE);
+		if (!install_dir) {
+			snprintf(out, out_size, "Error: Path too long.\n");
+			goto free;
+		}
+	}
+
+	snprintf(out, out_size, "Using DPDK source code from \"%s\".\n", install_dir);
+	out_size -= strlen(out);
+	out += strlen(out);
+
+	code_file = tokens[2];
+	length = strnlen(code_file, MAX_LINE_SIZE);
+	if ((length < 3) ||
+	    (code_file[length - 2] != '.') ||
+	    (code_file[length - 1] != 'c')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "code_file");
+		goto free;
+	}
+
+	lib_file = tokens[3];
+	length = strnlen(lib_file, MAX_LINE_SIZE);
+	if ((length < 4) ||
+	    (lib_file[length - 3] != '.') ||
+	    (lib_file[length - 2] != 's') ||
+	    (lib_file[length - 1] != 'o')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "lib_file");
+		goto free;
+	}
+
+	obj_file = malloc(length);
+	log_file = malloc(length + 2);
+	if (!obj_file || !log_file) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		goto free;
+	}
+
+	memcpy(obj_file, lib_file, length - 2);
+	obj_file[length - 2] = 'o';
+	obj_file[length - 1] = 0;
+
+	memcpy(log_file, lib_file, length - 2);
+	log_file[length - 2] = 'l';
+	log_file[length - 1] = 'o';
+	log_file[length] = 'g';
+	log_file[length + 1] = 0;
+
+	buffer = malloc(MAX_LINE_SIZE);
+	if (!buffer) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		return;
+	}
+
+	snprintf(buffer,
+		 MAX_LINE_SIZE,
+		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s %s "
+		 "-I %s/lib/pipeline "
+		 "-I %s/lib/eal/include "
+		 "-I %s/lib/eal/x86/include "
+		 "-I %s/lib/eal/include/generic "
+		 "-I %s/lib/meter "
+		 "-I %s/lib/port "
+		 "-I %s/lib/table "
+		 "-I %s/lib/pipeline "
+		 "-I %s/config "
+		 "-I %s/build "
+		 "-I %s/lib/eal/linux/include "
+		 ">%s 2>&1 "
+		 "&& "
+		 "gcc -shared %s -o %s "
+		 ">>%s 2>&1",
+		 obj_file,
+		 code_file,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 log_file,
+		 obj_file,
+		 lib_file,
+		 log_file);
+
+	status = system(buffer);
+	if (status) {
+		snprintf(out,
+			 out_size,
+			 "Library build failed, see file \"%s\" for details.\n",
+			 log_file);
+		goto free;
+	}
+
+free:
+	free(cwd);
+	free(obj_file);
+	free(log_file);
+	free(buffer);
+}
+
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
@@ -1127,10 +1266,6 @@ table_entry_free(struct rte_swx_table_entry *entry)
 	free(entry);
 }
 
-#ifndef MAX_LINE_SIZE
-#define MAX_LINE_SIZE 2048
-#endif
-
 static int
 pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p,
 			   const char *table_name,
@@ -3057,6 +3192,7 @@ cmd_help(char **tokens,
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
+			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3132,6 +3268,12 @@ cmd_help(char **tokens,
 		return;
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "libbuild") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_libbuild_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3417,6 +3559,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "libbuild") == 0)) {
+			cmd_pipeline_libbuild(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 11/17] examples/pipeline: remove the obsolete pipeline create CLI command
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (8 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
                         ` (6 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline configuration is now done through the I/O specification
file, hence this CLI command is no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 47 -----------------------------------------
 1 file changed, 47 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 28cf8d4178..7b725a9c27 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -523,39 +523,6 @@ cmd_tap(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_create_help[] =
-"pipeline <pipeline_name> create <numa_node>\n";
-
-static void
-cmd_pipeline_create(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	char *name;
-	uint32_t numa_node;
-
-	if (n_tokens != 4) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	name = tokens[1];
-
-	if (parser_read_uint32(&numa_node, tokens[3]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "numa_node");
-		return;
-	}
-
-	p = pipeline_create(obj, name, (int)numa_node);
-	if (!p) {
-		snprintf(out, out_size, "pipeline create error.");
-		return;
-	}
-}
-
 static const char cmd_pipeline_port_in_help[] =
 "pipeline <pipeline_name> port in <port_id>\n"
 "   link <link_name> rxq <queue_id> bsz <burst_size>\n"
@@ -3188,7 +3155,6 @@ cmd_help(char **tokens,
 			"\tmempool\n"
 			"\tlink\n"
 			"\ttap\n"
-			"\tpipeline create\n"
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
@@ -3241,12 +3207,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if ((strcmp(tokens[0], "pipeline") == 0) &&
-		(n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
-		snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
-		return;
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
 		if (strcmp(tokens[2], "in") == 0) {
@@ -3529,13 +3489,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 	}
 
 	if (strcmp(tokens[0], "pipeline") == 0) {
-		if ((n_tokens >= 3) &&
-			(strcmp(tokens[2], "create") == 0)) {
-			cmd_pipeline_create(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
 		if ((n_tokens >= 4) &&
 			(strcmp(tokens[2], "port") == 0) &&
 			(strcmp(tokens[3], "in") == 0)) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 12/17] examples/pipeline: remove the obsolete port configuration CLI commands
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (9 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
                         ` (5 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline I/O ports configuration is now done through the I/O
specification file, hence these CLI commands are no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 465 ----------------------------------------
 1 file changed, 465 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 7b725a9c27..b26e73c706 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -523,438 +523,6 @@ cmd_tap(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_port_in_help[] =
-"pipeline <pipeline_name> port in <port_id>\n"
-"   link <link_name> rxq <queue_id> bsz <burst_size>\n"
-"   ring <ring_name> bsz <burst_size>\n"
-"   | source <mempool_name> <file_name> loop <n_loops>\n"
-"   | tap <tap_name> mempool <mempool_name> mtu <mtu> bsz <burst_size>\n";
-
-static void
-cmd_pipeline_port_in(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	int status;
-	uint32_t port_id = 0, t0;
-
-	if (n_tokens < 6) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[2], "port") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
-		return;
-	}
-
-	if (strcmp(tokens[3], "in") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
-		return;
-	}
-
-	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-		return;
-	}
-
-	t0 = 5;
-
-	if (strcmp(tokens[t0], "link") == 0) {
-		struct rte_swx_port_ethdev_reader_params params;
-		struct link *link;
-
-		if (n_tokens < t0 + 6) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in link");
-			return;
-		}
-
-		link = link_find(obj, tokens[t0 + 1]);
-		if (!link) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"link_name");
-			return;
-		}
-		params.dev_name = link->dev_name;
-
-		if (strcmp(tokens[t0 + 2], "rxq") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
-			return;
-		}
-
-		if (parser_read_uint16(&params.queue_id, tokens[t0 + 3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"queue_id");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 4], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 5])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 6;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"ethdev",
-			&params);
-	} else if (strcmp(tokens[t0], "ring") == 0) {
-		struct rte_swx_port_ring_reader_params params;
-		struct ring *ring;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in ring");
-			return;
-		}
-
-		ring = ring_find(obj, tokens[t0 + 1]);
-		if (!ring) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"ring_name");
-			return;
-		}
-		params.name = ring->name;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"ring",
-			&params);
-	} else if (strcmp(tokens[t0], "source") == 0) {
-		struct rte_swx_port_source_params params;
-		struct mempool *mp;
-
-		if (n_tokens < t0 + 5) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in source");
-			return;
-		}
-
-		mp = mempool_find(obj, tokens[t0 + 1]);
-		if (!mp) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"mempool_name");
-			return;
-		}
-		params.pool = mp->m;
-
-		params.file_name = tokens[t0 + 2];
-
-		if (strcmp(tokens[t0 + 3], "loop") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "loop");
-			return;
-		}
-
-		if (parser_read_uint64(&params.n_loops, tokens[t0 + 4])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"n_loops");
-			return;
-		}
-
-		t0 += 5;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"source",
-			&params);
-	} else if (strcmp(tokens[t0], "tap") == 0) {
-		struct rte_swx_port_fd_reader_params params;
-		struct tap *tap;
-		struct mempool *mp;
-
-		if (n_tokens < t0 + 8) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in tap");
-			return;
-		}
-
-		tap = tap_find(obj, tokens[t0 + 1]);
-		if (!tap) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"tap_name");
-			return;
-		}
-		params.fd = tap->fd;
-
-		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
-				"mempool");
-			return;
-		}
-
-		mp = mempool_find(obj, tokens[t0 + 3]);
-		if (!mp) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"mempool_name");
-			return;
-		}
-		params.mempool = mp->m;
-
-		if (strcmp(tokens[t0 + 4], "mtu") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
-				"mtu");
-			return;
-		}
-
-		if (parser_read_uint32(&params.mtu, tokens[t0 + 5]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 6], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 7])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 8;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"fd",
-			&params);
-
-	} else {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (status) {
-		snprintf(out, out_size, "port in error.");
-		return;
-	}
-
-	if (n_tokens != t0) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-}
-
-static const char cmd_pipeline_port_out_help[] =
-"pipeline <pipeline_name> port out <port_id>\n"
-"   link <link_name> txq <txq_id> bsz <burst_size>\n"
-"   ring <ring_name> bsz <burst_size>\n"
-"   | sink <file_name> | none\n"
-"   | tap <tap_name> bsz <burst_size>\n";
-
-static void
-cmd_pipeline_port_out(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	int status;
-	uint32_t port_id = 0, t0;
-
-	if (n_tokens < 6) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[2], "port") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
-		return;
-	}
-
-	if (strcmp(tokens[3], "out") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
-		return;
-	}
-
-	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-		return;
-	}
-
-	t0 = 5;
-
-	if (strcmp(tokens[t0], "link") == 0) {
-		struct rte_swx_port_ethdev_writer_params params;
-		struct link *link;
-
-		if (n_tokens < t0 + 6) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out link");
-			return;
-		}
-
-		link = link_find(obj, tokens[t0 + 1]);
-		if (!link) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"link_name");
-			return;
-		}
-		params.dev_name = link->dev_name;
-
-		if (strcmp(tokens[t0 + 2], "txq") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
-			return;
-		}
-
-		if (parser_read_uint16(&params.queue_id, tokens[t0 + 3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"queue_id");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 4], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 5])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 6;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"ethdev",
-			&params);
-	} else if (strcmp(tokens[t0], "ring") == 0) {
-		struct rte_swx_port_ring_writer_params params;
-		struct ring *ring;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out link");
-			return;
-		}
-
-		ring = ring_find(obj, tokens[t0 + 1]);
-		if (!ring) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"ring_name");
-			return;
-		}
-		params.name = ring->name;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"ring",
-			&params);
-	} else if (strcmp(tokens[t0], "sink") == 0) {
-		struct rte_swx_port_sink_params params;
-
-		params.file_name = strcmp(tokens[t0 + 1], "none") ?
-			tokens[t0 + 1] : NULL;
-
-		t0 += 2;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"sink",
-			&params);
-	} else if (strcmp(tokens[t0], "tap") == 0) {
-		struct rte_swx_port_fd_writer_params params;
-		struct tap *tap;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out tap");
-			return;
-		}
-
-		tap = tap_find(obj, tokens[t0 + 1]);
-		if (!tap) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"tap_name");
-			return;
-		}
-		params.fd = tap->fd;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"fd",
-			&params);
-	} else {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (status) {
-		snprintf(out, out_size, "port out error.");
-		return;
-	}
-
-	if (n_tokens != t0) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-}
-
 static const char cmd_pipeline_codegen_help[] =
 "pipeline codegen <spec_file> <code_file>\n";
 
@@ -3155,8 +2723,6 @@ cmd_help(char **tokens,
 			"\tmempool\n"
 			"\tlink\n"
 			"\ttap\n"
-			"\tpipeline port in\n"
-			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
@@ -3207,21 +2773,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if ((strcmp(tokens[0], "pipeline") == 0) &&
-		(n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
-		if (strcmp(tokens[2], "in") == 0) {
-			snprintf(out, out_size, "\n%s\n",
-				cmd_pipeline_port_in_help);
-			return;
-		}
-
-		if (strcmp(tokens[2], "out") == 0) {
-			snprintf(out, out_size, "\n%s\n",
-				cmd_pipeline_port_out_help);
-			return;
-		}
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
@@ -3489,22 +3040,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 	}
 
 	if (strcmp(tokens[0], "pipeline") == 0) {
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "port") == 0) &&
-			(strcmp(tokens[3], "in") == 0)) {
-			cmd_pipeline_port_in(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "port") == 0) &&
-			(strcmp(tokens[3], "out") == 0)) {
-			cmd_pipeline_port_out(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[1], "codegen") == 0)) {
 			cmd_pipeline_codegen(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (10 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
                         ` (4 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline mirroring configuration is done through the I/O
specification file, so this CLI command is no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 76 -----------------------------------------
 1 file changed, 76 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index b26e73c706..fa828c008b 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -2457,68 +2457,6 @@ cmd_pipeline_stats(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_mirror_help[] =
-"pipeline <pipeline_name> mirror slots <n_slots> sessions <n_sessions>\n";
-
-static void
-cmd_pipeline_mirror(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct rte_swx_pipeline_mirroring_params params;
-	struct pipeline *p;
-	int status;
-
-	if (n_tokens != 7) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[0], "pipeline")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
-		return;
-	}
-
-	if (strcmp(tokens[2], "mirror")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror");
-		return;
-	}
-
-	if (strcmp(tokens[3], "slots")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "slots");
-		return;
-	}
-
-	if (parser_read_uint32(&params.n_slots, tokens[4])) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "n_slots");
-		return;
-	}
-
-	if (strcmp(tokens[5], "sessions")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "sessions");
-		return;
-	}
-
-	if (parser_read_uint32(&params.n_sessions, tokens[6])) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "n_sessions");
-		return;
-	}
-
-	status = rte_swx_pipeline_mirroring_config(p->p, &params);
-	if (status) {
-		snprintf(out, out_size, "Command failed!\n");
-		return;
-	}
-}
-
 static const char cmd_pipeline_mirror_session_help[] =
 "pipeline <pipeline_name> mirror session <session_id> port <port_id> clone fast | slow "
 "truncate <truncation_length>\n";
@@ -2746,7 +2684,6 @@ cmd_help(char **tokens,
 			"\tpipeline meter set\n"
 			"\tpipeline meter stats\n"
 			"\tpipeline stats\n"
-			"\tpipeline mirror\n"
 			"\tpipeline mirror session\n"
 			"\tthread pipeline enable\n"
 			"\tthread pipeline disable\n\n");
@@ -2958,12 +2895,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (!strcmp(tokens[0], "pipeline") &&
-		(n_tokens == 2) && !strcmp(tokens[1], "mirror")) {
-		snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_help);
-		return;
-	}
-
 	if (!strcmp(tokens[0], "pipeline") &&
 		(n_tokens == 3) && !strcmp(tokens[1], "mirror")
 		&& !strcmp(tokens[2], "session")) {
@@ -3217,13 +3148,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "mirror") == 0) &&
-			(strcmp(tokens[3], "slots") == 0)) {
-			cmd_pipeline_mirror(tokens, n_tokens, out, out_size, obj);
-			return;
-		}
-
 		if ((n_tokens >= 4) &&
 			(strcmp(tokens[2], "mirror") == 0) &&
 			(strcmp(tokens[3], "session") == 0)) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 14/17] examples/pipeline: use the pipeline name query API
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (11 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
                         ` (3 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Convert the CLI commands to use the pipeline name query API and remove
the linked list of pipeline objects previously maintained by the
application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c    | 268 ++++++++++++++++++++-----------------
 examples/pipeline/obj.c    |  67 ----------
 examples/pipeline/obj.h    |  24 ----
 examples/pipeline/thread.c |  65 ++++-----
 examples/pipeline/thread.h |   9 +-
 5 files changed, 175 insertions(+), 258 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index fa828c008b..f48ff326be 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -858,9 +858,9 @@ cmd_pipeline_table_add(char **tokens,
 		       uint32_t n_tokens,
 		       char *out,
 		       size_t out_size,
-		       void *obj)
+		       void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -872,8 +872,8 @@ cmd_pipeline_table_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -887,7 +887,7 @@ cmd_pipeline_table_add(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_entries_add(p->ctl,
+	status = pipeline_table_entries_add(ctl,
 					    table_name,
 					    file,
 					    &file_line_number);
@@ -956,9 +956,9 @@ cmd_pipeline_table_delete(char **tokens,
 			  uint32_t n_tokens,
 			  char *out,
 			  size_t out_size,
-			  void *obj)
+			  void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -970,8 +970,8 @@ cmd_pipeline_table_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -985,7 +985,7 @@ cmd_pipeline_table_delete(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_entries_delete(p->ctl,
+	status = pipeline_table_entries_delete(ctl,
 					       table_name,
 					       file,
 					       &file_line_number);
@@ -1054,9 +1054,9 @@ cmd_pipeline_table_default(char **tokens,
 			   uint32_t n_tokens,
 			   char *out,
 			   size_t out_size,
-			   void *obj)
+			   void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1068,8 +1068,8 @@ cmd_pipeline_table_default(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1083,7 +1083,7 @@ cmd_pipeline_table_default(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_default_entry_add(p->ctl,
+	status = pipeline_table_default_entry_add(ctl,
 						  table_name,
 						  file,
 						  &file_line_number);
@@ -1103,9 +1103,9 @@ cmd_pipeline_table_show(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name;
 	FILE *file = NULL;
 	int status;
@@ -1116,8 +1116,8 @@ cmd_pipeline_table_show(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1129,7 +1129,7 @@ cmd_pipeline_table_show(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_table_fprintf(file, p->ctl, table_name);
+	status = rte_swx_ctl_pipeline_table_fprintf(file, ctl, table_name);
 	if (status)
 		snprintf(out, out_size, MSG_ARG_INVALID, "table_name");
 
@@ -1145,9 +1145,9 @@ cmd_pipeline_selector_group_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	uint32_t group_id;
 	int status;
@@ -1158,8 +1158,8 @@ cmd_pipeline_selector_group_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1177,7 +1177,7 @@ cmd_pipeline_selector_group_add(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_group_add(p->ctl,
+	status = rte_swx_ctl_pipeline_selector_group_add(ctl,
 		selector_name,
 		&group_id);
 	if (status)
@@ -1194,9 +1194,9 @@ cmd_pipeline_selector_group_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	uint32_t group_id;
 	int status;
@@ -1207,8 +1207,8 @@ cmd_pipeline_selector_group_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1231,7 +1231,7 @@ cmd_pipeline_selector_group_delete(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_group_delete(p->ctl,
+	status = rte_swx_ctl_pipeline_selector_group_delete(ctl,
 		selector_name,
 		group_id);
 	if (status)
@@ -1402,9 +1402,9 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1416,8 +1416,8 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1443,7 +1443,7 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 		return;
 	}
 
-	status = pipeline_selector_group_members_add(p->ctl,
+	status = pipeline_selector_group_members_add(ctl,
 					    selector_name,
 					    file,
 					    &file_line_number);
@@ -1512,9 +1512,9 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1526,8 +1526,8 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1553,7 +1553,7 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 		return;
 	}
 
-	status = pipeline_selector_group_members_delete(p->ctl,
+	status = pipeline_selector_group_members_delete(ctl,
 					    selector_name,
 					    file,
 					    &file_line_number);
@@ -1573,9 +1573,9 @@ cmd_pipeline_selector_show(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	FILE *file = NULL;
 	int status;
@@ -1586,8 +1586,8 @@ cmd_pipeline_selector_show(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1600,7 +1600,7 @@ cmd_pipeline_selector_show(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_fprintf(file, p->ctl, selector_name);
+	status = rte_swx_ctl_pipeline_selector_fprintf(file, ctl, selector_name);
 	if (status)
 		snprintf(out, out_size, MSG_ARG_INVALID, "selector_name");
 
@@ -1665,9 +1665,9 @@ cmd_pipeline_learner_default(char **tokens,
 			     uint32_t n_tokens,
 			     char *out,
 			     size_t out_size,
-			     void *obj)
+			     void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *learner_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1679,8 +1679,8 @@ cmd_pipeline_learner_default(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1694,7 +1694,7 @@ cmd_pipeline_learner_default(char **tokens,
 		return;
 	}
 
-	status = pipeline_learner_default_entry_add(p->ctl,
+	status = pipeline_learner_default_entry_add(ctl,
 						    learner_name,
 						    file,
 						    &file_line_number);
@@ -1714,9 +1714,9 @@ cmd_pipeline_commit(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name;
 	int status;
 
@@ -1726,13 +1726,13 @@ cmd_pipeline_commit(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_commit(p->ctl, 1);
+	status = rte_swx_ctl_pipeline_commit(ctl, 1);
 	if (status)
 		snprintf(out, out_size, "Commit failed. "
 			"Use \"commit\" to retry or \"abort\" to discard the pending work.\n");
@@ -1746,9 +1746,9 @@ cmd_pipeline_abort(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name;
 
 	if (n_tokens != 3) {
@@ -1757,13 +1757,13 @@ cmd_pipeline_abort(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
 
-	rte_swx_ctl_pipeline_abort(p->ctl);
+	rte_swx_ctl_pipeline_abort(ctl);
 }
 
 static const char cmd_pipeline_regrd_help[] =
@@ -1774,9 +1774,9 @@ cmd_pipeline_regrd(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint64_t value;
 	uint32_t idx;
@@ -1787,8 +1787,8 @@ cmd_pipeline_regrd(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1805,7 +1805,7 @@ cmd_pipeline_regrd(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value);
+	status = rte_swx_ctl_pipeline_regarray_read(p, name, idx, &value);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1822,9 +1822,9 @@ cmd_pipeline_regwr(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint64_t value;
 	uint32_t idx;
@@ -1835,8 +1835,8 @@ cmd_pipeline_regwr(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1858,7 +1858,7 @@ cmd_pipeline_regwr(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value);
+	status = rte_swx_ctl_pipeline_regarray_write(p, name, idx, value);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1874,10 +1874,10 @@ cmd_pipeline_meter_profile_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_meter_trtcm_params params;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *profile_name;
 	int status;
 
@@ -1886,8 +1886,8 @@ cmd_pipeline_meter_profile_add(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1949,7 +1949,7 @@ cmd_pipeline_meter_profile_add(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_meter_profile_add(p->p, profile_name, &params);
+	status = rte_swx_ctl_meter_profile_add(p, profile_name, &params);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1964,9 +1964,9 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *profile_name;
 	int status;
 
@@ -1975,8 +1975,8 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1998,7 +1998,7 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_meter_profile_delete(p->p, profile_name);
+	status = rte_swx_ctl_meter_profile_delete(p, profile_name);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -2014,9 +2014,9 @@ cmd_pipeline_meter_reset(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2025,8 +2025,8 @@ cmd_pipeline_meter_reset(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2066,7 +2066,7 @@ cmd_pipeline_meter_reset(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_reset(p->p, name, idx0);
+		status = rte_swx_ctl_meter_reset(p, name, idx0);
 		if (status) {
 			snprintf(out, out_size, "Command failed for index %u.\n", idx0);
 			return;
@@ -2083,9 +2083,9 @@ cmd_pipeline_meter_set(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name, *profile_name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2094,8 +2094,8 @@ cmd_pipeline_meter_set(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2142,7 +2142,7 @@ cmd_pipeline_meter_set(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name);
+		status = rte_swx_ctl_meter_set(p, name, idx0, profile_name);
 		if (status) {
 			snprintf(out, out_size, "Command failed for index %u.\n", idx0);
 			return;
@@ -2159,10 +2159,10 @@ cmd_pipeline_meter_stats(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_ctl_meter_stats stats;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2171,8 +2171,8 @@ cmd_pipeline_meter_stats(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2235,7 +2235,7 @@ cmd_pipeline_meter_stats(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats);
+		status = rte_swx_ctl_meter_stats_read(p, name, idx0, &stats);
 		if (status) {
 			snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0);
 			out_size -= strlen(out);
@@ -2265,10 +2265,10 @@ cmd_pipeline_stats(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_ctl_pipeline_info info;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	uint32_t i;
 	int status;
 
@@ -2277,8 +2277,8 @@ cmd_pipeline_stats(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2288,7 +2288,7 @@ cmd_pipeline_stats(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_info_get(p->p, &info);
+	status = rte_swx_ctl_pipeline_info_get(p, &info);
 	if (status) {
 		snprintf(out, out_size, "Pipeline info get error.");
 		return;
@@ -2301,7 +2301,7 @@ cmd_pipeline_stats(char **tokens,
 	for (i = 0; i < info.n_ports_in; i++) {
 		struct rte_swx_port_in_stats stats;
 
-		rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats);
+		rte_swx_ctl_pipeline_port_in_stats_read(p, i, &stats);
 
 		snprintf(out, out_size, "\tPort %u:"
 			" packets %" PRIu64
@@ -2319,7 +2319,7 @@ cmd_pipeline_stats(char **tokens,
 	for (i = 0; i < info.n_ports_out; i++) {
 		struct rte_swx_port_out_stats stats;
 
-		rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats);
+		rte_swx_ctl_pipeline_port_out_stats_read(p, i, &stats);
 
 		if (i != info.n_ports_out - 1)
 			snprintf(out, out_size, "\tPort %u:", i);
@@ -2358,13 +2358,13 @@ cmd_pipeline_stats(char **tokens,
 		};
 		uint32_t j;
 
-		status = rte_swx_ctl_table_info_get(p->p, i, &table_info);
+		status = rte_swx_ctl_table_info_get(p, i, &table_info);
 		if (status) {
 			snprintf(out, out_size, "Table info get error.");
 			return;
 		}
 
-		status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats);
+		status = rte_swx_ctl_pipeline_table_stats_read(p, table_info.name, &stats);
 		if (status) {
 			snprintf(out, out_size, "Table stats read error.");
 			return;
@@ -2382,7 +2382,7 @@ cmd_pipeline_stats(char **tokens,
 		for (j = 0; j < info.n_actions; j++) {
 			struct rte_swx_ctl_action_info action_info;
 
-			status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
+			status = rte_swx_ctl_action_info_get(p, j, &action_info);
 			if (status) {
 				snprintf(out, out_size, "Action info get error.");
 				return;
@@ -2410,13 +2410,13 @@ cmd_pipeline_stats(char **tokens,
 		};
 		uint32_t j;
 
-		status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info);
+		status = rte_swx_ctl_learner_info_get(p, i, &learner_info);
 		if (status) {
 			snprintf(out, out_size, "Learner table info get error.");
 			return;
 		}
 
-		status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats);
+		status = rte_swx_ctl_pipeline_learner_stats_read(p, learner_info.name, &stats);
 		if (status) {
 			snprintf(out, out_size, "Learner table stats read error.");
 			return;
@@ -2442,7 +2442,7 @@ cmd_pipeline_stats(char **tokens,
 		for (j = 0; j < info.n_actions; j++) {
 			struct rte_swx_ctl_action_info action_info;
 
-			status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
+			status = rte_swx_ctl_action_info_get(p, j, &action_info);
 			if (status) {
 				snprintf(out, out_size, "Action info get error.");
 				return;
@@ -2466,10 +2466,10 @@ cmd_pipeline_mirror_session(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_pipeline_mirroring_session_params params;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	uint32_t session_id = 0;
 	int status;
 
@@ -2483,8 +2483,8 @@ cmd_pipeline_mirror_session(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2538,7 +2538,7 @@ cmd_pipeline_mirror_session(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_mirroring_session_set(p->p, session_id, &params);
+	status = rte_swx_ctl_pipeline_mirroring_session_set(p, session_id, &params);
 	if (status) {
 		snprintf(out, out_size, "Command failed!\n");
 		return;
@@ -2546,21 +2546,25 @@ cmd_pipeline_mirror_session(char **tokens,
 }
 
 static const char cmd_thread_pipeline_enable_help[] =
-"thread <thread_id> pipeline <pipeline_name> enable\n";
+"thread <thread_id> pipeline <pipeline_name> enable [ period <timer_period_ms> ]\n";
+
+#ifndef TIMER_PERIOD_MS_DEFAULT
+#define TIMER_PERIOD_MS_DEFAULT 10
+#endif
 
 static void
 cmd_thread_pipeline_enable(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	char *pipeline_name;
-	struct pipeline *p;
-	uint32_t thread_id;
+	struct rte_swx_pipeline *p;
+	uint32_t thread_id, timer_period_ms = TIMER_PERIOD_MS_DEFAULT;
 	int status;
 
-	if (n_tokens != 5) {
+	if ((n_tokens != 5) && (n_tokens != 7)) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
@@ -2576,8 +2580,8 @@ cmd_thread_pipeline_enable(char **tokens,
 	}
 
 	pipeline_name = tokens[3];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(pipeline_name);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2587,7 +2591,19 @@ cmd_thread_pipeline_enable(char **tokens,
 		return;
 	}
 
-	status = thread_pipeline_enable(thread_id, obj, pipeline_name);
+	if (n_tokens == 7) {
+		if (strcmp(tokens[5], "period") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
+			return;
+		}
+
+		if (parser_read_uint32(&timer_period_ms, tokens[6]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
+			return;
+		}
+	}
+
+	status = thread_pipeline_enable(thread_id, p, timer_period_ms);
 	if (status) {
 		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
 		return;
@@ -2602,9 +2618,9 @@ cmd_thread_pipeline_disable(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	char *pipeline_name;
 	uint32_t thread_id;
 	int status;
@@ -2625,8 +2641,8 @@ cmd_thread_pipeline_disable(char **tokens,
 	}
 
 	pipeline_name = tokens[3];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(pipeline_name);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2636,7 +2652,7 @@ cmd_thread_pipeline_disable(char **tokens,
 		return;
 	}
 
-	status = thread_pipeline_disable(thread_id, obj, pipeline_name);
+	status = thread_pipeline_disable(thread_id, p);
 	if (status) {
 		snprintf(out, out_size, MSG_CMD_FAIL,
 			"thread pipeline disable");
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index 967342c580..d1f519180e 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -16,7 +16,6 @@
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
-#include <rte_swx_pipeline.h>
 #include <rte_swx_ctl.h>
 
 #include "obj.h"
@@ -41,11 +40,6 @@ TAILQ_HEAD(ring_list, ring);
  */
 TAILQ_HEAD(tap_list, tap);
 
-/*
- * pipeline
- */
-TAILQ_HEAD(pipeline_list, pipeline);
-
 /*
  * obj
  */
@@ -53,7 +47,6 @@ struct obj {
 	struct mempool_list mempool_list;
 	struct link_list link_list;
 	struct ring_list ring_list;
-	struct pipeline_list pipeline_list;
 	struct tap_list tap_list;
 };
 
@@ -513,65 +506,6 @@ tap_create(struct obj *obj, const char *name)
 
 #endif
 
-/*
- * pipeline
- */
-#ifndef PIPELINE_MSGQ_SIZE
-#define PIPELINE_MSGQ_SIZE                                 64
-#endif
-
-struct pipeline *
-pipeline_create(struct obj *obj, const char *name, int numa_node)
-{
-	struct pipeline *pipeline;
-	struct rte_swx_pipeline *p = NULL;
-	int status;
-
-	/* Check input params */
-	if ((name == NULL) ||
-		pipeline_find(obj, name))
-		return NULL;
-
-	/* Resource create */
-	status = rte_swx_pipeline_config(&p, name, numa_node);
-	if (status)
-		goto error;
-
-	/* Node allocation */
-	pipeline = calloc(1, sizeof(struct pipeline));
-	if (pipeline == NULL)
-		goto error;
-
-	/* Node fill in */
-	strlcpy(pipeline->name, name, sizeof(pipeline->name));
-	pipeline->p = p;
-	pipeline->timer_period_ms = 10;
-
-	/* Node add to list */
-	TAILQ_INSERT_TAIL(&obj->pipeline_list, pipeline, node);
-
-	return pipeline;
-
-error:
-	rte_swx_pipeline_free(p);
-	return NULL;
-}
-
-struct pipeline *
-pipeline_find(struct obj *obj, const char *name)
-{
-	struct pipeline *pipeline;
-
-	if (!obj || !name)
-		return NULL;
-
-	TAILQ_FOREACH(pipeline, &obj->pipeline_list, node)
-		if (strcmp(name, pipeline->name) == 0)
-			return pipeline;
-
-	return NULL;
-}
-
 /*
  * obj
  */
@@ -587,7 +521,6 @@ obj_init(void)
 	TAILQ_INIT(&obj->mempool_list);
 	TAILQ_INIT(&obj->link_list);
 	TAILQ_INIT(&obj->ring_list);
-	TAILQ_INIT(&obj->pipeline_list);
 	TAILQ_INIT(&obj->tap_list);
 
 	return obj;
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index b921610554..e63a9c0e9a 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -143,28 +143,4 @@ tap_next(struct obj *obj, struct tap *tap);
 struct tap *
 tap_create(struct obj *obj, const char *name);
 
-/*
- * pipeline
- */
-struct pipeline {
-	TAILQ_ENTRY(pipeline) node;
-	char name[NAME_SIZE];
-
-	struct rte_swx_pipeline *p;
-	struct rte_swx_ctl_pipeline *ctl;
-
-	uint32_t timer_period_ms;
-	int enabled;
-	uint32_t thread_id;
-	uint32_t cpu_id;
-};
-
-struct pipeline *
-pipeline_create(struct obj *obj,
-		const char *name,
-		int numa_node);
-
-struct pipeline *
-pipeline_find(struct obj *obj, const char *name);
-
 #endif /* _INCLUDE_OBJ_H_ */
diff --git a/examples/pipeline/thread.c b/examples/pipeline/thread.c
index 5fe7eae00e..6d15f51fb2 100644
--- a/examples/pipeline/thread.c
+++ b/examples/pipeline/thread.c
@@ -228,20 +228,33 @@ thread_msg_send_recv(uint32_t thread_id,
 	return rsp;
 }
 
+static int
+thread_is_pipeline_enabled(uint32_t thread_id, struct rte_swx_pipeline *p)
+{
+	struct thread *t = &thread[thread_id];
+	struct thread_data *td = &thread_data[thread_id];
+	uint32_t i;
+
+	if (!t->enabled)
+		return 0; /* Pipeline NOT enabled on this thread. */
+
+	for (i = 0; i < td->n_pipelines; i++)
+		if (td->p[i] == p)
+			return 1; /* Pipeline enabled on this thread. */
+
+	return 0 /* Pipeline NOT enabled on this thread. */;
+}
+
 int
-thread_pipeline_enable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name)
+thread_pipeline_enable(uint32_t thread_id, struct rte_swx_pipeline *p, uint32_t timer_period_ms)
 {
-	struct pipeline *p = pipeline_find(obj, pipeline_name);
 	struct thread *t;
 	struct thread_msg_req *req;
 	struct thread_msg_rsp *rsp;
 	int status;
 
 	/* Check input params */
-	if ((thread_id >= RTE_MAX_LCORE) ||
-		(p == NULL))
+	if ((thread_id >= RTE_MAX_LCORE) || !p || !timer_period_ms)
 		return -1;
 
 	t = &thread[thread_id];
@@ -256,19 +269,14 @@ thread_pipeline_enable(uint32_t thread_id,
 			return -1;
 
 		/* Data plane thread */
-		td->p[td->n_pipelines] = p->p;
+		td->p[td->n_pipelines] = p;
 
-		tdp->p = p->p;
-		tdp->timer_period =
-			(rte_get_tsc_hz() * p->timer_period_ms) / 1000;
+		tdp->p = p;
+		tdp->timer_period = (rte_get_tsc_hz() * timer_period_ms) / 1000;
 		tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
 
 		td->n_pipelines++;
 
-		/* Pipeline */
-		p->thread_id = thread_id;
-		p->enabled = 1;
-
 		return 0;
 	}
 
@@ -279,8 +287,8 @@ thread_pipeline_enable(uint32_t thread_id,
 
 	/* Write request */
 	req->type = THREAD_REQ_PIPELINE_ENABLE;
-	req->pipeline_enable.p = p->p;
-	req->pipeline_enable.timer_period_ms = p->timer_period_ms;
+	req->pipeline_enable.p = p;
+	req->pipeline_enable.timer_period_ms = timer_period_ms;
 
 	/* Send request and wait for response */
 	rsp = thread_msg_send_recv(thread_id, req);
@@ -295,38 +303,28 @@ thread_pipeline_enable(uint32_t thread_id,
 	if (status)
 		return status;
 
-	p->thread_id = thread_id;
-	p->enabled = 1;
-
 	return 0;
 }
 
 int
-thread_pipeline_disable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name)
+thread_pipeline_disable(uint32_t thread_id, struct rte_swx_pipeline *p)
 {
-	struct pipeline *p = pipeline_find(obj, pipeline_name);
 	struct thread *t;
 	struct thread_msg_req *req;
 	struct thread_msg_rsp *rsp;
 	int status;
 
 	/* Check input params */
-	if ((thread_id >= RTE_MAX_LCORE) ||
-		(p == NULL))
+	if ((thread_id >= RTE_MAX_LCORE) || !p)
 		return -1;
 
 	t = &thread[thread_id];
 	if (t->enabled == 0)
 		return -1;
 
-	if (p->enabled == 0)
+	if (!thread_is_pipeline_enabled(thread_id, p))
 		return 0;
 
-	if (p->thread_id != thread_id)
-		return -1;
-
 	if (!thread_is_running(thread_id)) {
 		struct thread_data *td = &thread_data[thread_id];
 		uint32_t i;
@@ -334,7 +332,7 @@ thread_pipeline_disable(uint32_t thread_id,
 		for (i = 0; i < td->n_pipelines; i++) {
 			struct pipeline_data *tdp = &td->pipeline_data[i];
 
-			if (tdp->p != p->p)
+			if (tdp->p != p)
 				continue;
 
 			/* Data plane thread */
@@ -350,9 +348,6 @@ thread_pipeline_disable(uint32_t thread_id,
 
 			td->n_pipelines--;
 
-			/* Pipeline */
-			p->enabled = 0;
-
 			break;
 		}
 
@@ -366,7 +361,7 @@ thread_pipeline_disable(uint32_t thread_id,
 
 	/* Write request */
 	req->type = THREAD_REQ_PIPELINE_DISABLE;
-	req->pipeline_disable.p = p->p;
+	req->pipeline_disable.p = p;
 
 	/* Send request and wait for response */
 	rsp = thread_msg_send_recv(thread_id, req);
@@ -381,8 +376,6 @@ thread_pipeline_disable(uint32_t thread_id,
 	if (status)
 		return status;
 
-	p->enabled = 0;
-
 	return 0;
 }
 
diff --git a/examples/pipeline/thread.h b/examples/pipeline/thread.h
index d9d8645d4c..712cb25bbb 100644
--- a/examples/pipeline/thread.h
+++ b/examples/pipeline/thread.h
@@ -7,17 +7,16 @@
 
 #include <stdint.h>
 
-#include "obj.h"
+#include <rte_swx_pipeline.h>
 
 int
 thread_pipeline_enable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name);
+		       struct rte_swx_pipeline *p,
+		       uint32_t timer_period_ms);
 
 int
 thread_pipeline_disable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name);
+			struct rte_swx_pipeline *p);
 
 int
 thread_init(void);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 15/17] examples/pipeline: rework the link CLI command
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (12 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
                         ` (2 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Rework the link CLI command for better alignment with the naming
conventions used in the pipeline I/O specification file. Use the
library linked list of devices and remove the application list.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 81 +++++++++++++----------------------------
 examples/pipeline/obj.c | 16 ++------
 examples/pipeline/obj.h |  4 --
 3 files changed, 29 insertions(+), 72 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index f48ff326be..d56a830fb7 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -106,22 +106,6 @@ parser_read_uint32(uint32_t *value, const char *p)
 	return 0;
 }
 
-static int
-parser_read_uint16(uint16_t *value, const char *p)
-{
-	uint64_t val = 0;
-	int ret = parser_read_uint64(&val, p);
-
-	if (ret < 0)
-		return ret;
-
-	if (val > UINT16_MAX)
-		return -ERANGE;
-
-	*value = val;
-	return 0;
-}
-
 #define PARSE_DELIMITER " \f\n\r\t\v"
 
 static int
@@ -230,16 +214,15 @@ cmd_mempool(char **tokens,
 	}
 }
 
-static const char cmd_link_help[] =
-"link <link_name>\n"
-"   dev <device_name> | port <port_id>\n"
+static const char cmd_ethdev_help[] =
+"ethdev <ethdev_name>\n"
 "   rxq <n_queues> <queue_size> <mempool_name>\n"
 "   txq <n_queues> <queue_size>\n"
 "   promiscuous on | off\n"
 "   [rss <qid_0> ... <qid_n>]\n";
 
 static void
-cmd_link(char **tokens,
+cmd_ethdev(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
@@ -252,65 +235,51 @@ cmd_link(char **tokens,
 
 	memset(&p, 0, sizeof(p));
 
-	if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
+	if ((n_tokens < 11) || (n_tokens > 12 + LINK_RXQ_RSS_MAX)) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
 	name = tokens[1];
 
-	if (strcmp(tokens[2], "dev") == 0)
-		p.dev_name = tokens[3];
-	else if (strcmp(tokens[2], "port") == 0) {
-		p.dev_name = NULL;
-
-		if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-			return;
-		}
-	} else {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
-		return;
-	}
-
-	if (strcmp(tokens[4], "rxq") != 0) {
+	if (strcmp(tokens[2], "rxq") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
 		return;
 	}
 
-	if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
+	if (parser_read_uint32(&p.rx.n_queues, tokens[3]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
 		return;
 	}
-	if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
+	if (parser_read_uint32(&p.rx.queue_size, tokens[4]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
 		return;
 	}
 
-	p.rx.mempool_name = tokens[7];
+	p.rx.mempool_name = tokens[5];
 
-	if (strcmp(tokens[8], "txq") != 0) {
+	if (strcmp(tokens[6], "txq") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
 		return;
 	}
 
-	if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
+	if (parser_read_uint32(&p.tx.n_queues, tokens[7]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
 		return;
 	}
 
-	if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
+	if (parser_read_uint32(&p.tx.queue_size, tokens[8]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
 		return;
 	}
 
-	if (strcmp(tokens[11], "promiscuous") != 0) {
+	if (strcmp(tokens[9], "promiscuous") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
 		return;
 	}
 
-	if (strcmp(tokens[12], "on") == 0)
+	if (strcmp(tokens[10], "on") == 0)
 		p.promiscuous = 1;
-	else if (strcmp(tokens[12], "off") == 0)
+	else if (strcmp(tokens[10], "off") == 0)
 		p.promiscuous = 0;
 	else {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
@@ -319,10 +288,10 @@ cmd_link(char **tokens,
 
 	/* RSS */
 	p.rx.rss = NULL;
-	if (n_tokens > 13) {
+	if (n_tokens > 11) {
 		uint32_t queue_id, i;
 
-		if (strcmp(tokens[13], "rss") != 0) {
+		if (strcmp(tokens[11], "rss") != 0) {
 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
 			return;
 		}
@@ -330,7 +299,7 @@ cmd_link(char **tokens,
 		p.rx.rss = &rss;
 
 		rss.n_queues = 0;
-		for (i = 14; i < n_tokens; i++) {
+		for (i = 12; i < n_tokens; i++) {
 			if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
 				snprintf(out, out_size, MSG_ARG_INVALID,
 					"queue_id");
@@ -406,10 +375,10 @@ print_link_info(struct link *link, char *out, size_t out_size)
 }
 
 /*
- * link show [<link_name>]
+ * ethdev show [<ethdev_name>]
  */
 static void
-cmd_link_show(char **tokens,
+cmd_ethdev_show(char **tokens,
 	      uint32_t n_tokens,
 	      char *out,
 	      size_t out_size,
@@ -2675,7 +2644,7 @@ cmd_help(char **tokens,
 			"Type 'help <command>' for command details.\n\n"
 			"List of commands:\n"
 			"\tmempool\n"
-			"\tlink\n"
+			"\tethdev\n"
 			"\ttap\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
@@ -2711,8 +2680,8 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (strcmp(tokens[0], "link") == 0) {
-		snprintf(out, out_size, "\n%s\n", cmd_link_help);
+	if (strcmp(tokens[0], "ethdev") == 0) {
+		snprintf(out, out_size, "\n%s\n", cmd_ethdev_help);
 		return;
 	}
 
@@ -2966,13 +2935,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 		return;
 	}
 
-	if (strcmp(tokens[0], "link") == 0) {
+	if (strcmp(tokens[0], "ethdev") == 0) {
 		if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) {
-			cmd_link_show(tokens, n_tokens, out, out_size, obj);
+			cmd_ethdev_show(tokens, n_tokens, out, out_size, obj);
 			return;
 		}
 
-		cmd_link(tokens, n_tokens, out, out_size, obj);
+		cmd_ethdev(tokens, n_tokens, out, out_size, obj);
 		return;
 	}
 
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index d1f519180e..950ab831fb 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -181,7 +181,7 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 	struct mempool *mempool;
 	uint32_t cpu_id, i;
 	int status;
-	uint16_t port_id;
+	uint16_t port_id = 0;
 
 	/* Check input params */
 	if ((name == NULL) ||
@@ -193,16 +193,9 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 		(params->tx.queue_size == 0))
 		return NULL;
 
-	port_id = params->port_id;
-	if (params->dev_name) {
-		status = rte_eth_dev_get_port_by_name(params->dev_name,
-			&port_id);
-
-		if (status)
-			return NULL;
-	} else
-		if (!rte_eth_dev_is_valid_port(port_id))
-			return NULL;
+	status = rte_eth_dev_get_port_by_name(name, &port_id);
+	if (status)
+		return NULL;
 
 	if (rte_eth_dev_info_get(port_id, &port_info) != 0)
 		return NULL;
@@ -315,7 +308,6 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 	/* Node fill in */
 	strlcpy(link->name, name, sizeof(link->name));
 	link->port_id = port_id;
-	rte_eth_dev_get_name_by_port(port_id, link->dev_name);
 	link->n_rxq = params->rx.n_queues;
 	link->n_txq = params->tx.n_queues;
 
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index e63a9c0e9a..af270a8e57 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -63,9 +63,6 @@ struct link_params_rss {
 };
 
 struct link_params {
-	const char *dev_name;
-	uint16_t port_id; /**< Valid only when *dev_name* is NULL. */
-
 	struct {
 		uint32_t n_queues;
 		uint32_t queue_size;
@@ -84,7 +81,6 @@ struct link_params {
 struct link {
 	TAILQ_ENTRY(link) node;
 	char name[NAME_SIZE];
-	char dev_name[NAME_SIZE];
 	uint16_t port_id;
 	uint32_t n_rxq;
 	uint32_t n_txq;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 16/17] examples/pipelines: remove obsolete tap CLI command
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (13 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 22:54       ` [PATCH V4 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Remove the tap CLI command, as the file descriptor I/O ports of the
pipeline are now configured trough the I/O specification file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 37 -----------------
 examples/pipeline/obj.c | 89 -----------------------------------------
 examples/pipeline/obj.h | 18 ---------
 3 files changed, 144 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index d56a830fb7..75c32b9089 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -466,32 +466,6 @@ cmd_ring(char **tokens,
 	}
 }
 
-static const char cmd_tap_help[] =
-"tap <tap_name>\n";
-
-static void
-cmd_tap(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct tap *tap;
-	char *name;
-
-	if (n_tokens < 2) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-	name = tokens[1];
-
-	tap = tap_create(obj, name);
-	if (tap == NULL) {
-		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
-		return;
-	}
-}
-
 static const char cmd_pipeline_codegen_help[] =
 "pipeline codegen <spec_file> <code_file>\n";
 
@@ -2645,7 +2619,6 @@ cmd_help(char **tokens,
 			"List of commands:\n"
 			"\tmempool\n"
 			"\tethdev\n"
-			"\ttap\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
@@ -2690,11 +2663,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (strcmp(tokens[0], "tap") == 0) {
-		snprintf(out, out_size, "\n%s\n", cmd_tap_help);
-		return;
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
@@ -2950,11 +2918,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 		return;
 	}
 
-	if (strcmp(tokens[0], "tap") == 0) {
-		cmd_tap(tokens, n_tokens, out, out_size, obj);
-		return;
-	}
-
 	if (strcmp(tokens[0], "pipeline") == 0) {
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[1], "codegen") == 0)) {
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index 950ab831fb..b7e2316eec 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -35,11 +35,6 @@ TAILQ_HEAD(link_list, link);
  */
 TAILQ_HEAD(ring_list, ring);
 
-/*
- * tap
- */
-TAILQ_HEAD(tap_list, tap);
-
 /*
  * obj
  */
@@ -47,7 +42,6 @@ struct obj {
 	struct mempool_list mempool_list;
 	struct link_list link_list;
 	struct ring_list ring_list;
-	struct tap_list tap_list;
 };
 
 /*
@@ -416,88 +410,6 @@ ring_find(struct obj *obj, const char *name)
 	return NULL;
 }
 
-/*
- * tap
- */
-#define TAP_DEV		"/dev/net/tun"
-
-struct tap *
-tap_find(struct obj *obj, const char *name)
-{
-	struct tap *tap;
-
-	if (!obj || !name)
-		return NULL;
-
-	TAILQ_FOREACH(tap, &obj->tap_list, node)
-		if (strcmp(tap->name, name) == 0)
-			return tap;
-
-	return NULL;
-}
-
-struct tap *
-tap_next(struct obj *obj, struct tap *tap)
-{
-	return (tap == NULL) ?
-		TAILQ_FIRST(&obj->tap_list) : TAILQ_NEXT(tap, node);
-}
-
-#ifndef RTE_EXEC_ENV_LINUX
-
-struct tap *
-tap_create(struct obj *obj __rte_unused, const char *name __rte_unused)
-{
-	return NULL;
-}
-
-#else
-
-struct tap *
-tap_create(struct obj *obj, const char *name)
-{
-	struct tap *tap;
-	struct ifreq ifr;
-	int fd, status;
-
-	/* Check input params */
-	if ((name == NULL) ||
-		tap_find(obj, name))
-		return NULL;
-
-	/* Resource create */
-	fd = open(TAP_DEV, O_RDWR | O_NONBLOCK);
-	if (fd < 0)
-		return NULL;
-
-	memset(&ifr, 0, sizeof(ifr));
-	ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
-	strlcpy(ifr.ifr_name, name, IFNAMSIZ);
-
-	status = ioctl(fd, TUNSETIFF, (void *) &ifr);
-	if (status < 0) {
-		close(fd);
-		return NULL;
-	}
-
-	/* Node allocation */
-	tap = calloc(1, sizeof(struct tap));
-	if (tap == NULL) {
-		close(fd);
-		return NULL;
-	}
-	/* Node fill in */
-	strlcpy(tap->name, name, sizeof(tap->name));
-	tap->fd = fd;
-
-	/* Node add to list */
-	TAILQ_INSERT_TAIL(&obj->tap_list, tap, node);
-
-	return tap;
-}
-
-#endif
-
 /*
  * obj
  */
@@ -513,7 +425,6 @@ obj_init(void)
 	TAILQ_INIT(&obj->mempool_list);
 	TAILQ_INIT(&obj->link_list);
 	TAILQ_INIT(&obj->ring_list);
-	TAILQ_INIT(&obj->tap_list);
 
 	return obj;
 }
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index af270a8e57..8ea1c414c2 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -121,22 +121,4 @@ ring_create(struct obj *obj,
 struct ring *
 ring_find(struct obj *obj, const char *name);
 
-/*
- * tap
- */
-struct tap {
-	TAILQ_ENTRY(tap) node;
-	char name[NAME_SIZE];
-	int fd;
-};
-
-struct tap *
-tap_find(struct obj *obj, const char *name);
-
-struct tap *
-tap_next(struct obj *obj, struct tap *tap);
-
-struct tap *
-tap_create(struct obj *obj, const char *name);
-
 #endif /* _INCLUDE_OBJ_H_ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V4 17/17] examples/pipeline: call the code generation and build CLI commands
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (14 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
@ 2022-07-27 22:54       ` Cristian Dumitrescu
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 22:54 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Update the example CLI scripts with the commands for code generation
and shared object library build.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/examples/ethdev.io          | 27 +++++++++
 examples/pipeline/examples/fib.cli            | 44 +++++++-------
 examples/pipeline/examples/hash_func.cli      | 41 ++++++-------
 examples/pipeline/examples/l2fwd.cli          | 44 ++++++++------
 examples/pipeline/examples/l2fwd_macswp.cli   | 44 ++++++++------
 .../pipeline/examples/l2fwd_macswp_pcap.cli   | 35 +++++++----
 examples/pipeline/examples/l2fwd_pcap.cli     | 35 +++++++----
 examples/pipeline/examples/learner.cli        | 43 +++++++-------
 examples/pipeline/examples/meter.cli          | 58 +++++++++++--------
 examples/pipeline/examples/mirroring.cli      | 46 ++++++++-------
 examples/pipeline/examples/pcap.io            | 27 +++++++++
 examples/pipeline/examples/recirculation.cli  | 41 ++++++-------
 examples/pipeline/examples/registers.cli      | 53 +++++++++--------
 examples/pipeline/examples/selector.cli       | 55 +++++++++++-------
 examples/pipeline/examples/varbit.cli         | 41 ++++++-------
 examples/pipeline/examples/vxlan.cli          | 48 ++++++++++-----
 examples/pipeline/examples/vxlan_pcap.cli     | 39 +++++++++----
 17 files changed, 444 insertions(+), 277 deletions(-)
 create mode 100644 examples/pipeline/examples/ethdev.io
 create mode 100644 examples/pipeline/examples/pcap.io

diff --git a/examples/pipeline/examples/ethdev.io b/examples/pipeline/examples/ethdev.io
new file mode 100644
index 0000000000..cf2f3e20bd
--- /dev/null
+++ b/examples/pipeline/examples/ethdev.io
@@ -0,0 +1,27 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2022 Intel Corporation
+
+;
+; Pipeline packet mirroring.
+;
+mirroring slots 4 sessions 64
+
+;
+; Pipeline input ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port in 0 ethdev 0000:18:00.0 rxq 0 bsz 32
+port in 1 ethdev 0000:18:00.1 rxq 0 bsz 32
+port in 2 ethdev 0000:3b:00.0 rxq 0 bsz 32
+port in 3 ethdev 0000:3b:00.1 rxq 0 bsz 32
+
+;
+; Pipeline output ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port out 0 ethdev 0000:18:00.0 txq 0 bsz 32
+port out 1 ethdev 0000:18:00.1 txq 0 bsz 32
+port out 2 ethdev 0000:3b:00.0 txq 0 bsz 32
+port out 3 ethdev 0000:3b:00.1 txq 0 bsz 32
diff --git a/examples/pipeline/examples/fib.cli b/examples/pipeline/examples/fib.cli
index 93ab2b08f8..4e30c1320f 100644
--- a/examples/pipeline/examples/fib.cli
+++ b/examples/pipeline/examples/fib.cli
@@ -1,38 +1,38 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/fib.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/fib.spec /tmp/fib.c
+pipeline libbuild /tmp/fib.c /tmp/fib.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/fib.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/fib.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Initial set of table entries.
 ;
-; The table entries can later be updated at run-time through the CLI commands. Once the application
-; has been successfully started, the command to get the CLI prompt is: telnet 0.0.0.0 8086.
+; The table entries can later be updated at run-time through the CLI commands.
 ;
 pipeline PIPELINE0 table routing_table add ./examples/pipeline/examples/fib_routing_table.txt
 pipeline PIPELINE0 selector nexthop_group_table group add
diff --git a/examples/pipeline/examples/hash_func.cli b/examples/pipeline/examples/hash_func.cli
index d65cd62d17..b2e219e4c9 100644
--- a/examples/pipeline/examples/hash_func.cli
+++ b/examples/pipeline/examples/hash_func.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/hash_func.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/hash_func.spec /tmp/hash_func.c
+pipeline libbuild /tmp/hash_func.c /tmp/hash_func.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/hash_func.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/hash_func.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/l2fwd.cli b/examples/pipeline/examples/l2fwd.cli
index d89caf2d0a..27e37021b9 100644
--- a/examples/pipeline/examples/l2fwd.cli
+++ b/examples/pipeline/examples/l2fwd.cli
@@ -1,25 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd.so io ./examples/pipeline/examples/ethdev.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp.cli b/examples/pipeline/examples/l2fwd_macswp.cli
index 0f2a89ac5b..11bb4543b9 100644
--- a/examples/pipeline/examples/l2fwd_macswp.cli
+++ b/examples/pipeline/examples/l2fwd_macswp.cli
@@ -1,25 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_macswp.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd_macswp.so io ./examples/pipeline/examples/ethdev.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp_pcap.cli b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
index e9656fe3c2..8724dae3b0 100644
--- a/examples/pipeline/examples/l2fwd_macswp_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
@@ -1,20 +1,31 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-pipeline PIPELINE0 create 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_macswp_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd_macswp.so io ./examples/pipeline/examples/pcap.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_pcap.cli b/examples/pipeline/examples/l2fwd_pcap.cli
index 23fcb199f1..4db0a0dc56 100644
--- a/examples/pipeline/examples/l2fwd_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_pcap.cli
@@ -1,20 +1,31 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-pipeline PIPELINE0 create 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd.so io ./examples/pipeline/examples/pcap.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/learner.cli b/examples/pipeline/examples/learner.cli
index 688ce34f34..6c8aa3921e 100644
--- a/examples/pipeline/examples/learner.cli
+++ b/examples/pipeline/examples/learner.cli
@@ -1,36 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/learner.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/learner.spec /tmp/learner.c
+pipeline libbuild /tmp/learner.c /tmp/learner.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/learner.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/learner.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
 ;
 thread 1 pipeline PIPELINE0 enable
-
-; Once the application has started, the command to get the CLI prompt is: telnet 0.0.0.0 8086
diff --git a/examples/pipeline/examples/meter.cli b/examples/pipeline/examples/meter.cli
index b29ed24022..c1b88c882a 100644
--- a/examples/pipeline/examples/meter.cli
+++ b/examples/pipeline/examples/meter.cli
@@ -1,31 +1,43 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-; Example command line:
-;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/meter.cli
-
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/meter.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/meter.spec /tmp/meter.c
+pipeline libbuild /tmp/meter.c /tmp/meter.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/meter.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/meter.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 meter profile platinum add cir 46000000 pir 138000000 cbs 1000000 pbs 1000000
 pipeline PIPELINE0 meter meters from 0 to 15 set profile platinum
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/mirroring.cli b/examples/pipeline/examples/mirroring.cli
index 46d57db4ec..1d439e04d3 100644
--- a/examples/pipeline/examples/mirroring.cli
+++ b/examples/pipeline/examples/mirroring.cli
@@ -1,36 +1,38 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/mirroring.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/mirroring.spec /tmp/mirroring.c
+pipeline libbuild /tmp/mirroring.c /tmp/mirroring.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-pipeline PIPELINE0 mirror slots 4 sessions 16
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/mirroring.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/mirroring.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
-; Packet mirroring sessions.
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
 ;
 pipeline PIPELINE0 mirror session 0 port 1 clone fast truncate 0
 pipeline PIPELINE0 mirror session 1 port 2 clone slow truncate 0
diff --git a/examples/pipeline/examples/pcap.io b/examples/pipeline/examples/pcap.io
new file mode 100644
index 0000000000..111f61afae
--- /dev/null
+++ b/examples/pipeline/examples/pcap.io
@@ -0,0 +1,27 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2022 Intel Corporation
+
+;
+; Pipeline packet mirroring.
+;
+mirroring slots 4 sessions 64
+
+;
+; Pipeline input ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port in 0 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 1 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 2 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 3 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+
+;
+; Pipeline output ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port out 0 sink file none
+port out 1 sink file none
+port out 2 sink file none
+port out 3 sink file none
diff --git a/examples/pipeline/examples/recirculation.cli b/examples/pipeline/examples/recirculation.cli
index f855c5c327..52d0894f12 100644
--- a/examples/pipeline/examples/recirculation.cli
+++ b/examples/pipeline/examples/recirculation.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/recirculation.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/recirculation.spec /tmp/recirculation.c
+pipeline libbuild /tmp/recirculation.c /tmp/recirculation.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/recirculation.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/recirculation.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/registers.cli b/examples/pipeline/examples/registers.cli
index 8d026294cb..3516f76a5b 100644
--- a/examples/pipeline/examples/registers.cli
+++ b/examples/pipeline/examples/registers.cli
@@ -1,28 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-; Example command line:
-;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/registers.cli
-
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/registers.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/registers.spec /tmp/registers.c
+pipeline libbuild /tmp/registers.c /tmp/registers.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/registers.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/registers.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/selector.cli b/examples/pipeline/examples/selector.cli
index 123782c57b..f0e251b657 100644
--- a/examples/pipeline/examples/selector.cli
+++ b/examples/pipeline/examples/selector.cli
@@ -1,30 +1,45 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/selector.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/selector.spec /tmp/selector.c
+pipeline libbuild /tmp/selector.c /tmp/selector.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/selector.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/selector.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 selector s group add
 pipeline PIPELINE0 selector s group member add ./examples/pipeline/examples/selector.txt
 pipeline PIPELINE0 commit
 pipeline PIPELINE0 selector s show
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/varbit.cli b/examples/pipeline/examples/varbit.cli
index 9caeb9ca26..0f89990471 100644
--- a/examples/pipeline/examples/varbit.cli
+++ b/examples/pipeline/examples/varbit.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/varbit.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/varbit.spec /tmp/varbit.c
+pipeline libbuild /tmp/varbit.c /tmp/varbit.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/varbit.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/varbit.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/vxlan.cli b/examples/pipeline/examples/vxlan.cli
index 444f3f7bd8..1fbd1be6e4 100644
--- a/examples/pipeline/examples/vxlan.cli
+++ b/examples/pipeline/examples/vxlan.cli
@@ -1,27 +1,43 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/vxlan.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/vxlan.so io ./examples/pipeline/examples/ethdev.io numa 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/vxlan_pcap.cli b/examples/pipeline/examples/vxlan_pcap.cli
index 83fca8d0d9..adc7f73312 100644
--- a/examples/pipeline/examples/vxlan_pcap.cli
+++ b/examples/pipeline/examples/vxlan_pcap.cli
@@ -1,22 +1,39 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/vxlan_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/vxlan.so io ./examples/pipeline/examples/pcap.io numa 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 01/17] pipeline: add pipeline name
  2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
                         ` (15 preceding siblings ...)
  2022-07-27 22:54       ` [PATCH V4 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
@ 2022-07-27 23:01       ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
                           ` (16 more replies)
  16 siblings, 17 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add an unique name to every pipeline. This enables the library to
maintain a list of the existing pipeline objects, which can be
queried by the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/obj.c                  |   2 +-
 lib/pipeline/rte_swx_ctl.c               |  99 +++++++++++++++++++++
 lib/pipeline/rte_swx_ctl.h               |  15 ++++
 lib/pipeline/rte_swx_pipeline.c          | 107 ++++++++++++++++++++++-
 lib/pipeline/rte_swx_pipeline.h          |  18 +++-
 lib/pipeline/rte_swx_pipeline_internal.h |   2 +
 lib/pipeline/version.map                 |   4 +
 7 files changed, 244 insertions(+), 3 deletions(-)

diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index b79f044ac7..967342c580 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -533,7 +533,7 @@ pipeline_create(struct obj *obj, const char *name, int numa_node)
 		return NULL;
 
 	/* Resource create */
-	status = rte_swx_pipeline_config(&p, numa_node);
+	status = rte_swx_pipeline_config(&p, name, numa_node);
 	if (status)
 		goto error;
 
diff --git a/lib/pipeline/rte_swx_ctl.c b/lib/pipeline/rte_swx_ctl.c
index 710e89a46a..1b776fc543 100644
--- a/lib/pipeline/rte_swx_ctl.c
+++ b/lib/pipeline/rte_swx_ctl.c
@@ -9,6 +9,8 @@
 
 #include <rte_common.h>
 #include <rte_byteorder.h>
+#include <rte_tailq.h>
+#include <rte_eal_memconfig.h>
 
 #include <rte_swx_table_selector.h>
 
@@ -1157,12 +1159,103 @@ table_state_create(struct rte_swx_ctl_pipeline *ctl)
 	return status;
 }
 
+/* Global list of pipeline instances. */
+TAILQ_HEAD(rte_swx_ctl_pipeline_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_swx_ctl_pipeline_tailq = {
+	.name = "RTE_SWX_CTL_PIPELINE",
+};
+
+EAL_REGISTER_TAILQ(rte_swx_ctl_pipeline_tailq)
+
+struct rte_swx_ctl_pipeline *
+rte_swx_ctl_pipeline_find(const char *name)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	if (!name || !name[0] || (strnlen(name, RTE_SWX_CTL_NAME_SIZE) >= RTE_SWX_CTL_NAME_SIZE))
+		return NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_read_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		struct rte_swx_ctl_pipeline *ctl = (struct rte_swx_ctl_pipeline *)te->data;
+
+		if (!strncmp(name, ctl->info.name, sizeof(ctl->info.name))) {
+			rte_mcfg_tailq_read_unlock();
+			return ctl;
+		}
+	}
+
+	rte_mcfg_tailq_read_unlock();
+	return NULL;
+}
+
+static int
+ctl_register(struct rte_swx_ctl_pipeline *ctl)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		struct rte_swx_ctl_pipeline *ctl_crt = (struct rte_swx_ctl_pipeline *)te->data;
+
+		if (!strncmp(ctl->info.name, ctl_crt->info.name, sizeof(ctl->info.name))) {
+			rte_mcfg_tailq_write_unlock();
+			return -EEXIST;
+		}
+	}
+
+	te = calloc(1, sizeof(struct rte_tailq_entry));
+	if (!te) {
+		rte_mcfg_tailq_write_unlock();
+		return -ENOMEM;
+	}
+
+	te->data = (void *)ctl;
+	TAILQ_INSERT_TAIL(ctl_list, te, next);
+	rte_mcfg_tailq_write_unlock();
+	return 0;
+}
+
+static void
+ctl_unregister(struct rte_swx_ctl_pipeline *ctl)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		if (te->data == (void *)ctl) {
+			TAILQ_REMOVE(ctl_list, te, next);
+			rte_mcfg_tailq_write_unlock();
+			free(te);
+			return;
+		}
+	}
+
+	rte_mcfg_tailq_write_unlock();
+}
+
 void
 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
 {
 	if (!ctl)
 		return;
 
+	if (ctl->info.name[0])
+		ctl_unregister(ctl);
+
 	action_free(ctl);
 
 	table_state_free(ctl);
@@ -1441,6 +1534,12 @@ rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
 	if (status)
 		goto error;
 
+	if (ctl->info.name[0]) {
+		status = ctl_register(ctl);
+		if (status)
+			goto error;
+	}
+
 	return ctl;
 
 error:
diff --git a/lib/pipeline/rte_swx_ctl.h b/lib/pipeline/rte_swx_ctl.h
index d771389d26..63ee479e47 100644
--- a/lib/pipeline/rte_swx_ctl.h
+++ b/lib/pipeline/rte_swx_ctl.h
@@ -35,6 +35,9 @@ struct rte_swx_pipeline;
 
 /** Pipeline info. */
 struct rte_swx_ctl_pipeline_info {
+	/** Pipeline name. */
+	char name[RTE_SWX_CTL_NAME_SIZE];
+
 	/** Number of input ports. */
 	uint32_t n_ports_in;
 
@@ -812,6 +815,18 @@ rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p,
 /** Pipeline control opaque data structure. */
 struct rte_swx_ctl_pipeline;
 
+/**
+ * Pipeline control find
+ *
+ * @param[in] name
+ *   Pipeline name.
+ * @return
+ *   Valid pipeline control handle if found or NULL otherwise.
+ */
+__rte_experimental
+struct rte_swx_ctl_pipeline *
+rte_swx_ctl_pipeline_find(const char *name);
+
 /**
  * Pipeline control create
  *
diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index 3e1c6e9edb..c8ccded4f8 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -6,6 +6,8 @@
 #include <errno.h>
 #include <dlfcn.h>
 
+#include <rte_tailq.h>
+#include <rte_eal_memconfig.h>
 #include <rte_jhash.h>
 #include <rte_hash_crc.h>
 
@@ -9578,6 +9580,95 @@ metarray_free(struct rte_swx_pipeline *p)
 /*
  * Pipeline.
  */
+
+/* Global list of pipeline instances. */
+TAILQ_HEAD(rte_swx_pipeline_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_swx_pipeline_tailq = {
+	.name = "RTE_SWX_PIPELINE",
+};
+
+EAL_REGISTER_TAILQ(rte_swx_pipeline_tailq)
+
+struct rte_swx_pipeline *
+rte_swx_pipeline_find(const char *name)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	if (!name || !name[0] || (strnlen(name, RTE_SWX_NAME_SIZE) >= RTE_SWX_NAME_SIZE))
+		return NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_read_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		struct rte_swx_pipeline *p = (struct rte_swx_pipeline *)te->data;
+
+		if (!strncmp(name, p->name, sizeof(p->name))) {
+			rte_mcfg_tailq_read_unlock();
+			return p;
+		}
+	}
+
+	rte_mcfg_tailq_read_unlock();
+	return NULL;
+}
+
+static int
+pipeline_register(struct rte_swx_pipeline *p)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		struct rte_swx_pipeline *pipeline = (struct rte_swx_pipeline *)te->data;
+
+		if (!strncmp(p->name, pipeline->name, sizeof(p->name))) {
+			rte_mcfg_tailq_write_unlock();
+			return -EEXIST;
+		}
+	}
+
+	te = calloc(1, sizeof(struct rte_tailq_entry));
+	if (!te) {
+		rte_mcfg_tailq_write_unlock();
+		return -ENOMEM;
+	}
+
+	te->data = (void *)p;
+	TAILQ_INSERT_TAIL(pipeline_list, te, next);
+	rte_mcfg_tailq_write_unlock();
+	return 0;
+}
+
+static void
+pipeline_unregister(struct rte_swx_pipeline *p)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		if (te->data == (void *)p) {
+			TAILQ_REMOVE(pipeline_list, te, next);
+			rte_mcfg_tailq_write_unlock();
+			free(te);
+			return;
+		}
+	}
+
+	rte_mcfg_tailq_write_unlock();
+}
+
 void
 rte_swx_pipeline_free(struct rte_swx_pipeline *p)
 {
@@ -9586,6 +9677,9 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p)
 	if (!p)
 		return;
 
+	if (p->name[0])
+		pipeline_unregister(p);
+
 	lib = p->lib;
 
 	free(p->instruction_data);
@@ -9720,13 +9814,14 @@ hash_funcs_register(struct rte_swx_pipeline *p)
 }
 
 int
-rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
+rte_swx_pipeline_config(struct rte_swx_pipeline **p, const char *name, int numa_node)
 {
 	struct rte_swx_pipeline *pipeline = NULL;
 	int status = 0;
 
 	/* Check input parameters. */
 	CHECK(p, EINVAL);
+	CHECK(!name || (strnlen(name, RTE_SWX_NAME_SIZE) < RTE_SWX_NAME_SIZE), EINVAL);
 
 	/* Memory allocation. */
 	pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
@@ -9736,6 +9831,9 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
 	}
 
 	/* Initialization. */
+	if (name)
+		strcpy(pipeline->name, name);
+
 	TAILQ_INIT(&pipeline->struct_types);
 	TAILQ_INIT(&pipeline->port_in_types);
 	TAILQ_INIT(&pipeline->ports_in);
@@ -9776,6 +9874,12 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
 	if (status)
 		goto error;
 
+	if (pipeline->name[0]) {
+		status = pipeline_register(pipeline);
+		if (status)
+			goto error;
+	}
+
 	*p = pipeline;
 	return 0;
 
@@ -9966,6 +10070,7 @@ rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p,
 	TAILQ_FOREACH(table, &p->tables, node)
 		n_tables++;
 
+	strcpy(pipeline->name, p->name);
 	pipeline->n_ports_in = p->n_ports_in;
 	pipeline->n_ports_out = p->n_ports_out;
 	pipeline->n_mirroring_slots = p->n_mirroring_slots;
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index c41ca5cb15..ef50a0fa70 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -44,22 +44,38 @@ extern "C" {
 /** Pipeline opaque data structure. */
 struct rte_swx_pipeline;
 
+/**
+ * Pipeline find
+ *
+ * @param[in] name
+ *   Pipeline name.
+ * @return
+ *   Valid pipeline handle if found or NULL otherwise.
+ */
+__rte_experimental
+struct rte_swx_pipeline *
+rte_swx_pipeline_find(const char *name);
+
 /**
  * Pipeline configure
  *
  * @param[out] p
  *   Pipeline handle. Must point to valid memory. Contains valid pipeline handle
  *   when the function returns successfully.
+ * @param[in] name
+ *   Pipeline unique name.
  * @param[in] numa_node
  *   Non-Uniform Memory Access (NUMA) node.
  * @return
  *   0 on success or the following error codes otherwise:
  *   -EINVAL: Invalid argument;
- *   -ENOMEM: Not enough space/cannot allocate memory.
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -EEXIST: Pipeline with this name already exists.
  */
 __rte_experimental
 int
 rte_swx_pipeline_config(struct rte_swx_pipeline **p,
+			const char *name,
 			int numa_node);
 
 /*
diff --git a/lib/pipeline/rte_swx_pipeline_internal.h b/lib/pipeline/rte_swx_pipeline_internal.h
index a35635efb7..588cad62b5 100644
--- a/lib/pipeline/rte_swx_pipeline_internal.h
+++ b/lib/pipeline/rte_swx_pipeline_internal.h
@@ -1459,6 +1459,8 @@ instr_operand_nbo(struct thread *t, const struct instr_operand *x)
 #endif
 
 struct rte_swx_pipeline {
+	char name[RTE_SWX_NAME_SIZE];
+
 	struct struct_type_tailq struct_types;
 	struct port_in_type_tailq port_in_types;
 	struct port_in_tailq ports_in;
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 8312307a7a..50029aadcf 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -145,4 +145,8 @@ EXPERIMENTAL {
 	rte_swx_ctl_pipeline_learner_timeout_get;
 	rte_swx_ctl_pipeline_learner_timeout_set;
 	rte_swx_pipeline_hash_func_register;
+
+	#added in 22.11
+	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 02/17] pipeline: move specification data structures to internal header
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
                           ` (15 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Move all the pipeline object specification data structures to an
internal header file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 126 +------------------
 lib/pipeline/rte_swx_pipeline_spec.h | 176 +++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 125 deletions(-)
 create mode 100644 lib/pipeline/rte_swx_pipeline_spec.h

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 904b9eb471..5e07b4f794 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -9,7 +9,7 @@
 
 #include <rte_common.h>
 
-#include "rte_swx_pipeline.h"
+#include "rte_swx_pipeline_spec.h"
 
 #ifndef MAX_LINE_LENGTH
 #define MAX_LINE_LENGTH 2048
@@ -34,15 +34,7 @@
 
 /*
  * extobj.
- *
- * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
  */
-struct extobj_spec {
-	char *name;
-	char *extern_type_name;
-	char *pragma;
-};
-
 static void
 extobj_spec_free(struct extobj_spec *s)
 {
@@ -104,18 +96,7 @@ extobj_statement_parse(struct extobj_spec *s,
 /*
  * struct.
  *
- * struct STRUCT_TYPE_NAME {
- *	bit<SIZE> | varbit<SIZE> FIELD_NAME
- *	...
- * }
  */
-struct struct_spec {
-	char *name;
-	struct rte_swx_field_params *fields;
-	uint32_t n_fields;
-	int varbit;
-};
-
 static void
 struct_spec_free(struct struct_spec *s)
 {
@@ -293,13 +274,7 @@ struct_block_parse(struct struct_spec *s,
 /*
  * header.
  *
- * header HEADER_NAME instanceof STRUCT_TYPE_NAME
  */
-struct header_spec {
-	char *name;
-	char *struct_type_name;
-};
-
 static void
 header_spec_free(struct header_spec *s)
 {
@@ -351,12 +326,7 @@ header_statement_parse(struct header_spec *s,
 /*
  * metadata.
  *
- * metadata instanceof STRUCT_TYPE_NAME
  */
-struct metadata_spec {
-	char *struct_type_name;
-};
-
 static void
 metadata_spec_free(struct metadata_spec *s)
 {
@@ -400,18 +370,7 @@ metadata_statement_parse(struct metadata_spec *s,
 /*
  * action.
  *
- * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
- *	INSTRUCTION
- *	...
- * }
  */
-struct action_spec {
-	char *name;
-	char *args_struct_type_name;
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 action_spec_free(struct action_spec *s)
 {
@@ -540,29 +499,7 @@ action_block_parse(struct action_spec *s,
 /*
  * table.
  *
- * table TABLE_NAME {
- *	key {
- *		MATCH_FIELD_NAME exact | wildcard | lpm
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly ]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	instanceof TABLE_TYPE_NAME
- *	pragma ARGS
- *	size SIZE
- * }
  */
-struct table_spec {
-	char *name;
-	struct rte_swx_pipeline_table_params params;
-	char *recommended_table_type_name;
-	char *args;
-	uint32_t size;
-};
-
 static void
 table_spec_free(struct table_spec *s)
 {
@@ -1084,22 +1021,7 @@ table_block_parse(struct table_spec *s,
 /*
  * selector.
  *
- * selector SELECTOR_NAME {
- *	group_id FIELD_NAME
- *	selector {
- *		FIELD_NAME
- *		...
- *	}
- *	member_id FIELD_NAME
- *	n_groups N_GROUPS
- *	n_members_per_group N_MEMBERS_PER_GROUP
- * }
  */
-struct selector_spec {
-	char *name;
-	struct rte_swx_pipeline_selector_params params;
-};
-
 static void
 selector_spec_free(struct selector_spec *s)
 {
@@ -1385,31 +1307,7 @@ selector_block_parse(struct selector_spec *s,
 /*
  * learner.
  *
- * learner LEARNER_NAME {
- *	key {
- *		MATCH_FIELD_NAME
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	size SIZE
- *	timeout {
- *		TIMEOUT_IN_SECONDS
- *		...
- *	}
- * }
  */
-struct learner_spec {
-	char *name;
-	struct rte_swx_pipeline_learner_params params;
-	uint32_t size;
-	uint32_t *timeout;
-	uint32_t n_timeouts;
-};
-
 static void
 learner_spec_free(struct learner_spec *s)
 {
@@ -1958,14 +1856,7 @@ learner_block_parse(struct learner_spec *s,
 /*
  * regarray.
  *
- * regarray NAME size SIZE initval INITVAL
  */
-struct regarray_spec {
-	char *name;
-	uint64_t init_val;
-	uint32_t size;
-};
-
 static void
 regarray_spec_free(struct regarray_spec *s)
 {
@@ -2033,13 +1924,7 @@ regarray_statement_parse(struct regarray_spec *s,
 /*
  * metarray.
  *
- * metarray NAME size SIZE
  */
-struct metarray_spec {
-	char *name;
-	uint32_t size;
-};
-
 static void
 metarray_spec_free(struct metarray_spec *s)
 {
@@ -2095,16 +1980,7 @@ metarray_statement_parse(struct metarray_spec *s,
 /*
  * apply.
  *
- * apply {
- *	INSTRUCTION
- *	...
- * }
  */
-struct apply_spec {
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 apply_spec_free(struct apply_spec *s)
 {
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
new file mode 100644
index 0000000000..8458de878a
--- /dev/null
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Intel Corporation
+ */
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_common.h>
+
+#include <rte_swx_pipeline.h>
+
+/*
+ * extobj.
+ *
+ * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
+ */
+struct extobj_spec {
+	char *name;
+	char *extern_type_name;
+	char *pragma;
+};
+
+/*
+ * struct.
+ *
+ * struct STRUCT_TYPE_NAME {
+ *	bit<SIZE> | varbit<SIZE> FIELD_NAME
+ *	...
+ * }
+ */
+struct struct_spec {
+	char *name;
+	struct rte_swx_field_params *fields;
+	uint32_t n_fields;
+	int varbit;
+};
+
+/*
+ * header.
+ *
+ * header HEADER_NAME instanceof STRUCT_TYPE_NAME
+ */
+struct header_spec {
+	char *name;
+	char *struct_type_name;
+};
+
+/*
+ * metadata.
+ *
+ * metadata instanceof STRUCT_TYPE_NAME
+ */
+struct metadata_spec {
+	char *struct_type_name;
+};
+
+/*
+ * action.
+ *
+ * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct action_spec {
+	char *name;
+	char *args_struct_type_name;
+	const char **instructions;
+	uint32_t n_instructions;
+};
+
+/*
+ * table.
+ *
+ * table TABLE_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME exact | wildcard | lpm
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly ]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	instanceof TABLE_TYPE_NAME
+ *	pragma ARGS
+ *	size SIZE
+ * }
+ */
+struct table_spec {
+	char *name;
+	struct rte_swx_pipeline_table_params params;
+	char *recommended_table_type_name;
+	char *args;
+	uint32_t size;
+};
+
+/*
+ * selector.
+ *
+ * selector SELECTOR_NAME {
+ *	group_id FIELD_NAME
+ *	selector {
+ *		FIELD_NAME
+ *		...
+ *	}
+ *	member_id FIELD_NAME
+ *	n_groups N_GROUPS
+ *	n_members_per_group N_MEMBERS_PER_GROUP
+ * }
+ */
+struct selector_spec {
+	char *name;
+	struct rte_swx_pipeline_selector_params params;
+};
+
+/*
+ * learner.
+ *
+ * learner LEARNER_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	size SIZE
+ *	timeout {
+ *		TIMEOUT_IN_SECONDS
+ *		...
+ *	}
+ * }
+ */
+struct learner_spec {
+	char *name;
+	struct rte_swx_pipeline_learner_params params;
+	uint32_t size;
+	uint32_t *timeout;
+	uint32_t n_timeouts;
+};
+
+/*
+ * regarray.
+ *
+ * regarray NAME size SIZE initval INITVAL
+ */
+struct regarray_spec {
+	char *name;
+	uint64_t init_val;
+	uint32_t size;
+};
+
+/*
+ * metarray.
+ *
+ * metarray NAME size SIZE
+ */
+struct metarray_spec {
+	char *name;
+	uint32_t size;
+};
+
+/*
+ * apply.
+ *
+ * apply {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct apply_spec {
+	const char **instructions;
+	uint32_t n_instructions;
+};
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 03/17] pipeline: add pipeline specification data structure
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
                           ` (14 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add specification data structure for the entire pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 21 ++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h | 32 ++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 5e07b4f794..642091b678 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2082,6 +2082,27 @@ apply_block_parse(struct apply_spec *s,
 /*
  * Pipeline.
  */
+void
+pipeline_spec_free(struct pipeline_spec *s)
+{
+	if (!s)
+		return;
+
+	free(s->extobjs);
+	free(s->structs);
+	free(s->headers);
+	free(s->metadata);
+	free(s->actions);
+	free(s->tables);
+	free(s->selectors);
+	free(s->learners);
+	free(s->regarrays);
+	free(s->metarrays);
+	free(s->apply);
+
+	memset(s, 0, sizeof(struct pipeline_spec));
+}
+
 int
 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				 FILE *spec,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 8458de878a..e1170a33b1 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -174,3 +174,35 @@ struct apply_spec {
 	const char **instructions;
 	uint32_t n_instructions;
 };
+
+/*
+ * Pipeline.
+ */
+struct pipeline_spec {
+	struct extobj_spec *extobjs;
+	struct struct_spec *structs;
+	struct header_spec *headers;
+	struct metadata_spec *metadata;
+	struct action_spec *actions;
+	struct table_spec *tables;
+	struct selector_spec *selectors;
+	struct learner_spec *learners;
+	struct regarray_spec *regarrays;
+	struct metarray_spec *metarrays;
+	struct apply_spec *apply;
+
+	uint32_t n_extobjs;
+	uint32_t n_structs;
+	uint32_t n_headers;
+	uint32_t n_metadata;
+	uint32_t n_actions;
+	uint32_t n_tables;
+	uint32_t n_selectors;
+	uint32_t n_learners;
+	uint32_t n_regarrays;
+	uint32_t n_metarrays;
+	uint32_t n_apply;
+};
+
+void
+pipeline_spec_free(struct pipeline_spec *s);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 04/17] pipeline: rework the specification file-based pipeline build
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
                           ` (13 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Rework the specification file-based pipeline build operation to first
parse the specification file into the previously introduced pipeline
specification data structure, then use this structure to configure
and build the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 478 +++++++++++++++++++++------
 lib/pipeline/rte_swx_pipeline_spec.h |   9 +
 2 files changed, 385 insertions(+), 102 deletions(-)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 642091b678..62929a9da6 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2103,11 +2103,10 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg)
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg)
 {
 	struct extobj_spec extobj_spec = {0};
 	struct struct_spec struct_spec = {0};
@@ -2120,26 +2119,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	struct regarray_spec regarray_spec = {0};
 	struct metarray_spec metarray_spec = {0};
 	struct apply_spec apply_spec = {0};
-	uint32_t n_lines;
+	struct pipeline_spec *s = NULL;
+	uint32_t n_lines = 0;
 	uint32_t block_mask = 0;
-	int status;
+	int status = 0;
 
 	/* Check the input arguments. */
-	if (!p) {
+	if (!spec) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null pipeline argument.";
+			*err_msg = "Invalid input argument.";
 		status = -EINVAL;
 		goto error;
 	}
 
-	if (!spec) {
+	/* Memory allocation. */
+	s = calloc(sizeof(struct pipeline_spec), 1);
+	if (!s) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null specification file argument.";
-		status = -EINVAL;
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
 		goto error;
 	}
 
@@ -2200,6 +2202,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* struct block. */
 		if (block_mask & (1 << STRUCT_BLOCK)) {
+			struct struct_spec *new_structs;
+
 			status = struct_block_parse(&struct_spec,
 						    &block_mask,
 						    tokens,
@@ -2214,26 +2218,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_struct_type_register(p,
-				struct_spec.name,
-				struct_spec.fields,
-				struct_spec.n_fields,
-				struct_spec.varbit);
-			if (status) {
+			new_structs = realloc(s->structs,
+					      (s->n_structs + 1) * sizeof(struct struct_spec));
+			if (!new_structs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Struct registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			struct_spec_free(&struct_spec);
+			s->structs = new_structs;
+			memcpy(&s->structs[s->n_structs], &struct_spec, sizeof(struct struct_spec));
+			s->n_structs++;
+			memset(&struct_spec, 0, sizeof(struct struct_spec));
 
 			continue;
 		}
 
 		/* action block. */
 		if (block_mask & (1 << ACTION_BLOCK)) {
+			struct action_spec *new_actions;
+
 			status = action_block_parse(&action_spec,
 						    &block_mask,
 						    tokens,
@@ -2248,26 +2255,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_action_config(p,
-				action_spec.name,
-				action_spec.args_struct_type_name,
-				action_spec.instructions,
-				action_spec.n_instructions);
-			if (status) {
+			new_actions = realloc(s->actions,
+					      (s->n_actions + 1) * sizeof(struct action_spec));
+			if (!new_actions) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Action config error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			action_spec_free(&action_spec);
+			s->actions = new_actions;
+			memcpy(&s->actions[s->n_actions], &action_spec, sizeof(struct action_spec));
+			s->n_actions++;
+			memset(&action_spec, 0, sizeof(struct action_spec));
 
 			continue;
 		}
 
 		/* table block. */
 		if (block_mask & (1 << TABLE_BLOCK)) {
+			struct table_spec *new_tables;
+
 			status = table_block_parse(&table_spec,
 						   &block_mask,
 						   tokens,
@@ -2282,27 +2292,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_table_config(p,
-				table_spec.name,
-				&table_spec.params,
-				table_spec.recommended_table_type_name,
-				table_spec.args,
-				table_spec.size);
-			if (status) {
+			new_tables = realloc(s->tables,
+					     (s->n_tables + 1) * sizeof(struct table_spec));
+			if (!new_tables) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			table_spec_free(&table_spec);
+			s->tables = new_tables;
+			memcpy(&s->tables[s->n_tables], &table_spec, sizeof(struct table_spec));
+			s->n_tables++;
+			memset(&table_spec, 0, sizeof(struct table_spec));
 
 			continue;
 		}
 
 		/* selector block. */
 		if (block_mask & (1 << SELECTOR_BLOCK)) {
+			struct selector_spec *new_selectors;
+
 			status = selector_block_parse(&selector_spec,
 						      &block_mask,
 						      tokens,
@@ -2317,24 +2329,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_selector_config(p,
-				selector_spec.name,
-				&selector_spec.params);
-			if (status) {
+			new_selectors = realloc(s->selectors,
+				(s->n_selectors + 1) * sizeof(struct selector_spec));
+			if (!new_selectors) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Selector configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			selector_spec_free(&selector_spec);
+			s->selectors = new_selectors;
+			memcpy(&s->selectors[s->n_selectors],
+			       &selector_spec,
+			       sizeof(struct selector_spec));
+			s->n_selectors++;
+			memset(&selector_spec, 0, sizeof(struct selector_spec));
 
 			continue;
 		}
 
 		/* learner block. */
 		if (block_mask & (1 << LEARNER_BLOCK)) {
+			struct learner_spec *new_learners;
+
 			status = learner_block_parse(&learner_spec,
 						     &block_mask,
 						     tokens,
@@ -2349,27 +2368,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_learner_config(p,
-				learner_spec.name,
-				&learner_spec.params,
-				learner_spec.size,
-				learner_spec.timeout,
-				learner_spec.n_timeouts);
-			if (status) {
+			new_learners = realloc(s->learners,
+					       (s->n_learners + 1) * sizeof(struct learner_spec));
+			if (!new_learners) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Learner table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			learner_spec_free(&learner_spec);
+			s->learners = new_learners;
+			memcpy(&s->learners[s->n_learners],
+			       &learner_spec,
+			       sizeof(struct learner_spec));
+			s->n_learners++;
+			memset(&learner_spec, 0, sizeof(struct learner_spec));
 
 			continue;
 		}
 
 		/* apply block. */
 		if (block_mask & (1 << APPLY_BLOCK)) {
+			struct apply_spec *new_apply;
+
 			status = apply_block_parse(&apply_spec,
 						   &block_mask,
 						   tokens,
@@ -2384,24 +2407,28 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_instructions_config(p,
-				apply_spec.instructions,
-				apply_spec.n_instructions);
-			if (status) {
+			new_apply = realloc(s->apply, (s->n_apply + 1) * sizeof(struct apply_spec));
+			if (!new_apply) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Pipeline instructions err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			apply_spec_free(&apply_spec);
+			s->apply = new_apply;
+			memcpy(&s->apply[s->n_apply], &apply_spec, sizeof(struct apply_spec));
+			s->n_apply++;
+			memset(&apply_spec, 0, sizeof(struct apply_spec));
 
 			continue;
 		}
 
 		/* extobj. */
 		if (!strcmp(tokens[0], "extobj")) {
+			struct extobj_spec *new_extobjs;
+
 			status = extobj_statement_parse(&extobj_spec,
 							tokens,
 							n_tokens,
@@ -2411,19 +2438,21 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_extern_object_config(p,
-				extobj_spec.name,
-				extobj_spec.extern_type_name,
-				extobj_spec.pragma);
-			if (status) {
+			new_extobjs = realloc(s->extobjs,
+					      (s->n_extobjs + 1) * sizeof(struct extobj_spec));
+			if (!new_extobjs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Extern object config err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			extobj_spec_free(&extobj_spec);
+			s->extobjs = new_extobjs;
+			memcpy(&s->extobjs[s->n_extobjs], &extobj_spec, sizeof(struct extobj_spec));
+			s->n_extobjs++;
+			memset(&extobj_spec, 0, sizeof(struct extobj_spec));
 
 			continue;
 		}
@@ -2445,6 +2474,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* header. */
 		if (!strcmp(tokens[0], "header")) {
+			struct header_spec *new_headers;
+
 			status = header_statement_parse(&header_spec,
 							tokens,
 							n_tokens,
@@ -2454,24 +2485,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_header_register(p,
-				header_spec.name,
-				header_spec.struct_type_name);
-			if (status) {
+			new_headers = realloc(s->headers,
+					      (s->n_headers + 1) * sizeof(struct header_spec));
+			if (!new_headers) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Header registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			header_spec_free(&header_spec);
+			s->headers = new_headers;
+			memcpy(&s->headers[s->n_headers], &header_spec, sizeof(struct header_spec));
+			s->n_headers++;
+			memset(&header_spec, 0, sizeof(struct header_spec));
 
 			continue;
 		}
 
 		/* metadata. */
 		if (!strcmp(tokens[0], "metadata")) {
+			struct metadata_spec *new_metadata;
+
 			status = metadata_statement_parse(&metadata_spec,
 							  tokens,
 							  n_tokens,
@@ -2481,17 +2517,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_metadata_register(p,
-				metadata_spec.struct_type_name);
-			if (status) {
+			new_metadata = realloc(s->metadata,
+					       (s->n_metadata + 1) * sizeof(struct metadata_spec));
+			if (!new_metadata) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meta-data reg err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metadata_spec_free(&metadata_spec);
+			s->metadata = new_metadata;
+			memcpy(&s->metadata[s->n_metadata],
+			       &metadata_spec,
+			       sizeof(struct metadata_spec));
+			s->n_metadata++;
+			memset(&metadata_spec, 0, sizeof(struct metadata_spec));
 
 			continue;
 		}
@@ -2558,6 +2600,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* regarray. */
 		if (!strcmp(tokens[0], "regarray")) {
+			struct regarray_spec *new_regarrays;
+
 			status = regarray_statement_parse(&regarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2567,25 +2611,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_regarray_config(p,
-				regarray_spec.name,
-				regarray_spec.size,
-				regarray_spec.init_val);
-			if (status) {
+			new_regarrays = realloc(s->regarrays,
+				(s->n_regarrays + 1) * sizeof(struct regarray_spec));
+			if (!new_regarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Register array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			regarray_spec_free(&regarray_spec);
+			s->regarrays = new_regarrays;
+			memcpy(&s->regarrays[s->n_regarrays],
+			       &regarray_spec,
+			       sizeof(struct regarray_spec));
+			s->n_regarrays++;
+			memset(&regarray_spec, 0, sizeof(struct regarray_spec));
 
 			continue;
 		}
 
 		/* metarray. */
 		if (!strcmp(tokens[0], "metarray")) {
+			struct metarray_spec *new_metarrays;
+
 			status = metarray_statement_parse(&metarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2595,18 +2645,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_metarray_config(p,
-				metarray_spec.name,
-				metarray_spec.size);
-			if (status) {
+			new_metarrays = realloc(s->metarrays,
+				(s->n_metarrays + 1) * sizeof(struct metarray_spec));
+			if (!new_metarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meter array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metarray_spec_free(&metarray_spec);
+			s->metarrays = new_metarrays;
+			memcpy(&s->metarrays[s->n_metarrays],
+			       &metarray_spec,
+			       sizeof(struct metarray_spec));
+			s->n_metarrays++;
+			memset(&metarray_spec, 0, sizeof(struct metarray_spec));
 
 			continue;
 		}
@@ -2644,17 +2699,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 		goto error;
 	}
 
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = n_lines;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
+	return s;
 
 error:
 	extobj_spec_free(&extobj_spec);
@@ -2668,5 +2713,234 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	regarray_spec_free(&regarray_spec);
 	metarray_spec_free(&metarray_spec);
 	apply_spec_free(&apply_spec);
+	pipeline_spec_free(s);
+
+	return NULL;
+}
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg)
+{
+	uint32_t i;
+	int status = 0;
+
+	/* extobj. */
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		status = rte_swx_pipeline_extern_object_config(p,
+			extobj_spec->name,
+			extobj_spec->extern_type_name,
+			extobj_spec->pragma);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Extern object configuration error.";
+			return status;
+		}
+	}
+
+	/* regarray. */
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		status = rte_swx_pipeline_regarray_config(p,
+			regarray_spec->name,
+			regarray_spec->size,
+			regarray_spec->init_val);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Register array configuration error.";
+			return status;
+		}
+	}
+
+	/* metarray. */
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		status = rte_swx_pipeline_metarray_config(p,
+			metarray_spec->name,
+			metarray_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meter array configuration error.";
+			return status;
+		}
+	}
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		status = rte_swx_pipeline_struct_type_register(p,
+			struct_spec->name,
+			struct_spec->fields,
+			struct_spec->n_fields,
+			struct_spec->varbit);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Struct type registration error.";
+			return status;
+		}
+	}
+
+	/* header. */
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		status = rte_swx_pipeline_packet_header_register(p,
+			header_spec->name,
+			header_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Header configuration error.";
+			return status;
+		}
+	}
+
+	/* metadata. */
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		status = rte_swx_pipeline_packet_metadata_register(p,
+			metadata_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meta-data registration error.";
+			return status;
+		}
+	}
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		status = rte_swx_pipeline_action_config(p,
+			action_spec->name,
+			action_spec->args_struct_type_name,
+			action_spec->instructions,
+			action_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Action configuration error.";
+			return status;
+		}
+	}
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		status = rte_swx_pipeline_table_config(p,
+			table_spec->name,
+			&table_spec->params,
+			table_spec->recommended_table_type_name,
+			table_spec->args,
+			table_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Table configuration error.";
+			return status;
+		}
+	}
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		status = rte_swx_pipeline_selector_config(p,
+			selector_spec->name,
+			&selector_spec->params);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Selector table configuration error.";
+			return status;
+		}
+	}
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		status = rte_swx_pipeline_learner_config(p,
+			learner_spec->name,
+			&learner_spec->params,
+			learner_spec->size,
+			learner_spec->timeout,
+			learner_spec->n_timeouts);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Learner table configuration error.";
+			return status;
+		}
+	}
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+
+		status = rte_swx_pipeline_instructions_config(p,
+			apply_spec->instructions,
+			apply_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline instructions configuration error.";
+			return status;
+		}
+	}
+
+	return 0;
+}
+
+int
+rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
+				 FILE *spec_file,
+				 uint32_t *err_line,
+				 const char **err_msg)
+{
+	struct pipeline_spec *s = NULL;
+	int status = 0;
+
+	/* Check the input arguments. */
+	if (!p || !spec_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Spec file parse. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Pipeline configure. */
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto error;
+	}
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline build error.";
+		goto error;
+	}
+
+	return 0;
+
+error:
+	pipeline_spec_free(s);
 	return status;
 }
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index e1170a33b1..4f3a0b5958 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,3 +206,12 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg);
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 05/17] pipeline: generate the code for pipeline specification structure
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (2 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
                           ` (12 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add support to export the pipeline specification data structure to a C
source code file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 622 +++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h |   5 +
 2 files changed, 627 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 62929a9da6..bf21fe17ba 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2020 Intel Corporation
  */
 #include <stdint.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -2103,6 +2104,627 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
+static const char *
+match_type_string_get(enum rte_swx_table_match_type match_type)
+{
+	switch (match_type) {
+	case RTE_SWX_TABLE_MATCH_WILDCARD: return "RTE_SWX_TABLE_MATCH_WILDCARD";
+	case RTE_SWX_TABLE_MATCH_LPM: return "RTE_SWX_TABLE_MATCH_LPM";
+	case RTE_SWX_TABLE_MATCH_EXACT: return "RTE_SWX_TABLE_MATCH_EXACT";
+	default: return "RTE_SWX_TABLE_MATCH_UNKNOWN";
+	}
+}
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s)
+{
+	uint32_t i;
+
+	/* Check the input arguments. */
+	if (!f || !s)
+		return;
+
+	/* extobj. */
+	fprintf(f, "static struct extobj_spec extobjs[] = {\n");
+
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", extobj_spec->name);
+		fprintf(f, "\t\t.extern_type_name = \"%s\",\n", extobj_spec->extern_type_name);
+		if (extobj_spec->pragma)
+			fprintf(f, "\t\t.pragma = \"%s\",\n", extobj_spec->pragma);
+		else
+			fprintf(f, "\t\t.pragma = NULL,\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* regarray. */
+	fprintf(f, "static struct regarray_spec regarrays[] = {\n");
+
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", regarray_spec->name);
+		fprintf(f, "\t\t.init_val = %" PRIu64 ",\n", regarray_spec->init_val);
+		fprintf(f, "\t\t.size = %u,\n", regarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metarray. */
+	fprintf(f, "static struct metarray_spec metarrays[] = {\n");
+
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", metarray_spec->name);
+		fprintf(f, "\t\t.size = %u,\n", metarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+		uint32_t j;
+
+		fprintf(f, "static struct rte_swx_field_params struct_%s_fields[] = {\n",
+			struct_spec->name);
+
+		for (j = 0; j < struct_spec->n_fields; j++) {
+			struct rte_swx_field_params *field = &struct_spec->fields[j];
+
+			fprintf(f, "\t[%d] = {\n", j);
+			fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+			fprintf(f, "\t\t.n_bits = %u,\n", field->n_bits);
+			fprintf(f, "\t},\n");
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct struct_spec structs[] = {\n");
+
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", struct_spec->name);
+		fprintf(f, "\t\t.fields = struct_%s_fields,\n", struct_spec->name);
+		fprintf(f, "\t\t.n_fields = "
+			"sizeof(struct_%s_fields) / sizeof(struct_%s_fields[0]),\n",
+			struct_spec->name,
+			struct_spec->name);
+		fprintf(f, "\t\t.varbit = %d,\n", struct_spec->varbit);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* header. */
+	fprintf(f, "static struct header_spec headers[] = {\n");
+
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", header_spec->name);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", header_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metadata. */
+	fprintf(f, "static struct metadata_spec metadata[] = {\n");
+
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", metadata_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *action_%s_initial_instructions[] = {\n",
+			action_spec->name);
+
+		for (j = 0; j < action_spec->n_instructions; j++) {
+			const char *instr = action_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct action_spec actions[] = {\n");
+
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", action_spec->name);
+
+		if (action_spec->args_struct_type_name)
+			fprintf(f, "\t\t.args_struct_type_name = \"%s\",\n",
+				action_spec->args_struct_type_name);
+		else
+			fprintf(f, "\t\t.args_struct_type_name = NULL,\n");
+
+		fprintf(f, "\t\t.instructions = action_%s_initial_instructions,\n",
+			action_spec->name);
+		fprintf(f, "\t\t.n_instructions = "
+			"sizeof(action_%s_initial_instructions) / "
+			"sizeof(action_%s_initial_instructions[0]),\n",
+			action_spec->name,
+			action_spec->name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+		uint32_t j;
+
+		/* fields. */
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "static struct rte_swx_match_field_params "
+				"table_%s_fields[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_fields; j++) {
+				struct rte_swx_match_field_params *field =
+					&table_spec->params.fields[j];
+
+				fprintf(f, "\t[%d] = {\n", j);
+				fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+				fprintf(f, "\t\t.match_type = %s,\n",
+					match_type_string_get(field->match_type));
+				fprintf(f, "\t},\n");
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (table_spec->params.action_names && table_spec->params.n_actions) {
+			fprintf(f, "static const char *table_%s_action_names[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				const char *action_name = table_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (table_spec->params.action_is_for_table_entries &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_table_entries[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (table_spec->params.action_is_for_default_entry &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_default_entry[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct table_spec tables[] = {\n");
+
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", table_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.fields = table_%s_fields,\n", table_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(table_%s_fields) / sizeof(table_%s_fields[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.fields = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (table_spec->params.action_names && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = table_%s_action_names,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (table_spec->params.action_is_for_table_entries && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"table_%s_action_is_for_table_entries,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (table_spec->params.action_is_for_default_entry && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"table_%s_action_is_for_default_entry,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = sizeof(table_%s_action_names) / "
+				"sizeof(table_%s_action_names[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = 0,\n");
+
+		if (table_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				table_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (table_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				table_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			table_spec->params.default_action_is_const);
+		fprintf(f, "\t\t},\n");
+
+		if (table_spec->recommended_table_type_name)
+			fprintf(f, "\t\t.recommended_table_type_name = \"%s\",\n",
+				table_spec->recommended_table_type_name);
+		else
+			fprintf(f, "\t\t.recommended_table_type_name = NULL,\n");
+
+		if (table_spec->args)
+			fprintf(f, "\t\t.args = \"%s\",\n", table_spec->args);
+		else
+			fprintf(f, "\t\t.args = NULL,\n");
+
+		fprintf(f, "\t\t.size = %u,\n", table_spec->size);
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+		uint32_t j;
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "static const char *selector_%s_field_names[] = {\n",
+				selector_spec->name);
+
+			for (j = 0; j < selector_spec->params.n_selector_fields; j++) {
+				const char *field_name =
+					selector_spec->params.selector_field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct selector_spec selectors[] = {\n");
+
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+
+		fprintf(f, "\t\t.name = \"%s\",\n", selector_spec->name);
+		fprintf(f, "\t\t.params = {\n");
+
+		if (selector_spec->params.group_id_field_name)
+			fprintf(f, "\t\t\t.group_id_field_name = \"%s\",\n",
+				selector_spec->params.group_id_field_name);
+		else
+			fprintf(f, "\t\t\t.group_id_field_name = NULL,\n");
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "\t\t\t.selector_field_names = selector_%s_field_names,\n",
+				selector_spec->name);
+			fprintf(f, "\t\t\t.n_selector_fields = "
+				"sizeof(selector_%s_field_names) / sizeof(selector_%s_field_names[0]),\n",
+				selector_spec->name,
+				selector_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.selector_field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_selector_fields = 0,\n");
+		}
+
+		if (selector_spec->params.member_id_field_name)
+			fprintf(f, "\t\t\t.member_id_field_name = \"%s\",\n",
+				selector_spec->params.member_id_field_name);
+		else
+			fprintf(f, "\t\t\t.member_id_field_name = NULL,\n");
+
+		fprintf(f, "\t\t\t.n_groups_max = %u,\n", selector_spec->params.n_groups_max);
+
+		fprintf(f, "\t\t\t.n_members_per_group_max = %u,\n",
+			selector_spec->params.n_members_per_group_max);
+
+		fprintf(f, "\t\t},\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+		uint32_t j;
+
+		/* field_names. */
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "static const char *learner_%s_field_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_fields; j++) {
+				const char *field_name = learner_spec->params.field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (learner_spec->params.action_names && learner_spec->params.n_actions) {
+			fprintf(f, "static const char *learner_%s_action_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				const char *action_name = learner_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_table_entries[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_default_entry[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* timeout. */
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "static uint32_t learner_%s_timeout[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->n_timeouts; j++) {
+				uint32_t value = learner_spec->timeout[j];
+
+				fprintf(f, "\t[%d] = %u,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct learner_spec learners[] = {\n");
+
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", learner_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.field_names = learner_%s_field_names,\n",
+				learner_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(learner_%s_field_names) / "
+				"sizeof(learner_%s_field_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = learner_%s_action_names,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"learner_%s_action_is_for_table_entries,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"learner_%s_action_is_for_default_entry,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = "
+				"sizeof(learner_%s_action_names) / sizeof(learner_%s_action_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = NULL,\n");
+
+		if (learner_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				learner_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (learner_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				learner_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			learner_spec->params.default_action_is_const);
+
+		fprintf(f, "\t\t},\n");
+
+		fprintf(f, "\t\t.size = %u,\n", learner_spec->size);
+
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "\t\t.timeout = learner_%s_timeout,\n", learner_spec->name);
+			fprintf(f, "\t\t\t.n_timeouts = "
+				"sizeof(learner_%s_timeout) / sizeof(learner_%s_timeout[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t.timeout = NULL,\n");
+			fprintf(f, "\t\t\t.n_timeouts = 0,\n");
+		}
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *apply%u_initial_instructions[] = {\n", i);
+
+		for (j = 0; j < apply_spec->n_instructions; j++) {
+			const char *instr = apply_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct apply_spec apply[] = {\n");
+
+	for (i = 0; i < s->n_apply; i++) {
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t.instructions = apply%u_initial_instructions,\n", i);
+		fprintf(f, "\t.n_instructions = "
+			"sizeof(apply%u_initial_instructions) / "
+			"sizeof(apply%u_initial_instructions[0]),\n",
+			i,
+			i);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* pipeline. */
+	fprintf(f, "struct pipeline_spec pipeline_spec = {\n");
+	fprintf(f, "\t.extobjs = extobjs,\n");
+	fprintf(f, "\t.structs = structs,\n");
+	fprintf(f, "\t.headers = headers,\n");
+	fprintf(f, "\t.metadata = metadata,\n");
+	fprintf(f, "\t.actions = actions,\n");
+	fprintf(f, "\t.tables = tables,\n");
+	fprintf(f, "\t.selectors = selectors,\n");
+	fprintf(f, "\t.learners = learners,\n");
+	fprintf(f, "\t.regarrays = regarrays,\n");
+	fprintf(f, "\t.metarrays = metarrays,\n");
+	fprintf(f, "\t.apply = apply,\n");
+	fprintf(f, "\t.n_extobjs = sizeof(extobjs) / sizeof(extobjs[0]),\n");
+	fprintf(f, "\t.n_structs = sizeof(structs) / sizeof(structs[0]),\n");
+	fprintf(f, "\t.n_headers = sizeof(headers) / sizeof(headers[0]),\n");
+	fprintf(f, "\t.n_metadata = sizeof(metadata) / sizeof(metadata[0]),\n");
+	fprintf(f, "\t.n_actions = sizeof(actions) / sizeof(actions[0]),\n");
+	fprintf(f, "\t.n_tables = sizeof(tables) / sizeof(tables[0]),\n");
+	fprintf(f, "\t.n_selectors = sizeof(selectors) / sizeof(selectors[0]),\n");
+	fprintf(f, "\t.n_learners = sizeof(learners) / sizeof(learners[0]),\n");
+	fprintf(f, "\t.n_regarrays = sizeof(regarrays) / sizeof(regarrays[0]),\n");
+	fprintf(f, "\t.n_metarrays = sizeof(metarrays) / sizeof(metarrays[0]),\n");
+	fprintf(f, "\t.n_apply = sizeof(apply) / sizeof(apply[0]),\n");
+	fprintf(f, "};\n");
+}
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 4f3a0b5958..707b99ba09 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,6 +206,11 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s);
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 06/17] pipeline: add support for pipeline I/O specification
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (3 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
                           ` (11 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add specification data structure and API for the pipeline I/O ports
and related pipeline configuration such as packet mirroring.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 852 +++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h |  58 ++
 2 files changed, 910 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index bf21fe17ba..f34803793d 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -9,6 +9,12 @@
 #include <errno.h>
 
 #include <rte_common.h>
+#include <rte_mempool.h>
+
+#include <rte_swx_port_ethdev.h>
+#include <rte_swx_port_ring.h>
+#include <rte_swx_port_source_sink.h>
+#include <rte_swx_port_fd.h>
 
 #include "rte_swx_pipeline_spec.h"
 
@@ -3566,3 +3572,849 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	pipeline_spec_free(s);
 	return status;
 }
+
+static void
+port_in_params_free(void *params, const char *port_type)
+{
+	uintptr_t dev_name;
+
+	if (!params || !port_type)
+		return;
+
+	if (!strcmp(port_type, "ethdev")) {
+		struct rte_swx_port_ethdev_reader_params *p = params;
+
+		dev_name = (uintptr_t)p->dev_name;
+	} else if (!strcmp(port_type, "ring")) {
+		struct rte_swx_port_ring_reader_params *p = params;
+
+		dev_name = (uintptr_t)p->name;
+	} else if (!strcmp(port_type, "source")) {
+		struct rte_swx_port_source_params *p = params;
+
+		dev_name = (uintptr_t)p->file_name;
+	} else
+		dev_name = (uintptr_t)NULL;
+
+	free((void *)dev_name);
+	free(params);
+}
+
+static void
+port_out_params_free(void *params, const char *port_type)
+{
+	uintptr_t dev_name;
+
+	if (!params || !port_type)
+		return;
+
+	if (!strcmp(port_type, "ethdev")) {
+		struct rte_swx_port_ethdev_writer_params *p = params;
+
+		dev_name = (uintptr_t)p->dev_name;
+	} else if (!strcmp(port_type, "ring")) {
+		struct rte_swx_port_ring_writer_params *p = params;
+
+		dev_name = (uintptr_t)p->name;
+	} else if (!strcmp(port_type, "sink")) {
+		struct rte_swx_port_sink_params *p = params;
+
+		dev_name = (uintptr_t)p->file_name;
+	} else
+		dev_name = (uintptr_t)NULL;
+
+	free((void *)dev_name);
+	free(params);
+}
+
+void
+pipeline_iospec_free(struct pipeline_iospec *s)
+{
+	uint32_t i;
+
+	if (!s)
+		return;
+
+	/* Input ports. */
+	for (i = 0; i < s->n_ports_in; i++) {
+		uintptr_t name = (uintptr_t)s->port_in_type[i];
+
+		port_in_params_free(s->port_in_params[i], s->port_in_type[i]);
+		free((void *)name);
+	}
+
+	free(s->port_in_type);
+	free(s->port_in_params);
+
+	/* Output ports. */
+	for (i = 0; i < s->n_ports_out; i++) {
+		uintptr_t name = (uintptr_t)s->port_out_type[i];
+
+		port_out_params_free(s->port_out_params[i], s->port_out_type[i]);
+		free((void *)name);
+	}
+
+	free(s->port_out_type);
+	free(s->port_out_params);
+
+	free(s);
+}
+
+static int
+mirroring_parse(struct rte_swx_pipeline_mirroring_params *p,
+		char **tokens,
+		uint32_t n_tokens,
+		const char **err_msg)
+{
+	char *token;
+
+	if ((n_tokens != 4) || strcmp(tokens[0], "slots") || strcmp(tokens[2], "sessions")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return -EINVAL;
+	}
+
+	/* <n_slots>. */
+	token = tokens[1];
+	p->n_slots = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_slots> parameter.";
+		return -EINVAL;
+	}
+
+	/* <n_sessions>. */
+	token = tokens[3];
+	p->n_sessions = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_sessions> parameter.";
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+port_in_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ethdev_reader_params *p = NULL;
+	char *token, *dev_name = NULL;
+	uint32_t queue_id, burst_size;
+
+	if ((n_tokens != 5) || strcmp(tokens[1], "rxq") || strcmp(tokens[3], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <queue_id>. */
+	token = tokens[2];
+	queue_id = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <queue_id> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[4];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	dev_name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ethdev_reader_params));
+	if (!dev_name || !p) {
+		free(dev_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->dev_name = dev_name;
+	p->queue_id = queue_id;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_in_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ring_reader_params *p = NULL;
+	char *token, *name = NULL;
+	uint32_t burst_size;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ring_reader_params));
+	if (!name || !p) {
+		free(name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->name = name;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_in_source_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_source_params *p = NULL;
+	struct rte_mempool *pool = NULL;
+	char *token, *file_name = NULL;
+	uint32_t n_loops, n_pkts_max;
+
+	if ((n_tokens != 8) ||
+	    strcmp(tokens[0], "mempool") ||
+	    strcmp(tokens[2], "file") ||
+	    strcmp(tokens[4], "loop") ||
+	    strcmp(tokens[6], "packets")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <mempool_name>. */
+	pool = rte_mempool_lookup(tokens[1]);
+	if (!pool) {
+		if (err_msg)
+			*err_msg = "Invalid <mempool_name> parameter.";
+		return NULL;
+	}
+
+	/* <n_loops>. */
+	token = tokens[5];
+	n_loops = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_loops> parameter.";
+		return NULL;
+	}
+
+	/* <n_pkts_max>. */
+	token = tokens[7];
+	n_pkts_max = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_pkts_max> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	file_name = strdup(tokens[3]);
+	p = malloc(sizeof(struct rte_swx_port_source_params));
+	if (!file_name || !p) {
+		free(file_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->pool = pool;
+	p->file_name = file_name;
+	p->n_loops = n_loops;
+	p->n_pkts_max = n_pkts_max;
+
+	return p;
+}
+
+static void *
+port_in_fd_parse(char **tokens,
+		 uint32_t n_tokens,
+		 const char **err_msg)
+{
+	struct rte_swx_port_fd_reader_params *p = NULL;
+	struct rte_mempool *mempool = NULL;
+	char *token;
+	uint32_t mtu, burst_size;
+	int fd;
+
+	if ((n_tokens != 7) ||
+	    strcmp(tokens[1], "mtu") ||
+	    strcmp(tokens[3], "mempool") ||
+	    strcmp(tokens[5], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <file_descriptor>. */
+	token = tokens[0];
+	fd = strtol(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <file_descriptor> parameter.";
+		return NULL;
+	}
+
+	/* <mtu>. */
+	token = tokens[2];
+	mtu = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <mtu> parameter.";
+		return NULL;
+	}
+
+	/* <mempool_name>. */
+	mempool = rte_mempool_lookup(tokens[4]);
+	if (!mempool) {
+		if (err_msg)
+			*err_msg = "Invalid <mempool_name> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[6];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	p = malloc(sizeof(struct rte_swx_port_fd_reader_params));
+	if (!p) {
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->fd = fd;
+	p->mtu = mtu;
+	p->mempool = mempool;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ethdev_writer_params *p = NULL;
+	char *token, *dev_name = NULL;
+	uint32_t queue_id, burst_size;
+
+	if ((n_tokens != 5) || strcmp(tokens[1], "txq") || strcmp(tokens[3], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <queue_id>. */
+	token = tokens[2];
+	queue_id = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <queue_id> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[4];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	dev_name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ethdev_writer_params));
+	if (!dev_name || !p) {
+		free(dev_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->dev_name = dev_name;
+	p->queue_id = queue_id;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ring_writer_params *p = NULL;
+	char *token, *name = NULL;
+	uint32_t burst_size;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
+	if (!name || !p) {
+		free(name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->name = name;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_sink_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_sink_params *p = NULL;
+	char *file_name = NULL;
+	int file_name_valid = 0;
+
+	if ((n_tokens != 2) || strcmp(tokens[0], "file")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	if (strcmp(tokens[1], "none")) {
+		file_name_valid = 1;
+		file_name = strdup(tokens[1]);
+	}
+
+	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
+	if ((file_name_valid && !file_name) || !p) {
+		free(file_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->file_name = file_name;
+
+	return p;
+}
+
+static void *
+port_out_fd_parse(char **tokens,
+		  uint32_t n_tokens,
+		  const char **err_msg)
+{
+	struct rte_swx_port_fd_writer_params *p = NULL;
+	char *token;
+	uint32_t burst_size;
+	int fd;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <file_descriptor>. */
+	token = tokens[0];
+	fd = strtol(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <file_descriptor> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	p = malloc(sizeof(struct rte_swx_port_fd_writer_params));
+	if (!p) {
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->fd = fd;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+struct pipeline_iospec *
+pipeline_iospec_parse(FILE *spec,
+		      uint32_t *err_line,
+		      const char **err_msg)
+{
+	struct pipeline_iospec *s = NULL;
+	uint32_t n_lines = 0;
+
+	/* Check the input arguments. */
+	if (!spec) {
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		goto error;
+	}
+
+	/* Memory allocation. */
+	s = calloc(sizeof(struct pipeline_iospec), 1);
+	if (!s) {
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		goto error;
+	}
+
+	/* Initialize with the default values. */
+	s->mirroring_params.n_slots = RTE_SWX_PACKET_MIRRORING_SLOTS_DEFAULT;
+	s->mirroring_params.n_sessions = RTE_SWX_PACKET_MIRRORING_SESSIONS_DEFAULT;
+
+	for (n_lines = 1; ; n_lines++) {
+		char line[MAX_LINE_LENGTH];
+		char *tokens[MAX_TOKENS], *ptr = line;
+		uint32_t n_tokens = 0;
+
+		/* Read next line. */
+		if (!fgets(line, sizeof(line), spec))
+			break;
+
+		/* Parse the line into tokens. */
+		for ( ; ; ) {
+			char *token;
+
+			/* Get token. */
+			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
+			if (!token)
+				break;
+
+			/* Handle comments. */
+			if ((token[0] == '#') ||
+			    (token[0] == ';') ||
+			    ((token[0] == '/') && (token[1] == '/'))) {
+				break;
+			}
+
+			/* Handle excessively long lines. */
+			if (n_tokens >= RTE_DIM(tokens)) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Too many tokens.";
+				goto error;
+			}
+
+			/* Handle excessively long tokens. */
+			if (strnlen(token, RTE_SWX_NAME_SIZE) >=
+			    RTE_SWX_NAME_SIZE) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Token too big.";
+				goto error;
+			}
+
+			/* Save token. */
+			tokens[n_tokens] = token;
+			n_tokens++;
+		}
+
+		/* Handle empty lines. */
+		if (!n_tokens)
+			continue;
+
+		/* mirroring. */
+		if ((n_tokens >= 1) && !strcmp(tokens[0], "mirroring")) {
+			int status = 0;
+
+			status = mirroring_parse(&s->mirroring_params,
+						 &tokens[1],
+						 n_tokens - 1,
+						 err_msg);
+			if (status) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			continue;
+		}
+
+		/* port in. */
+		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "in")) {
+			char *token = tokens[2];
+			uint32_t *new_id = NULL;
+			const char **new_type = NULL, *port_type = NULL;
+			void **new_params = NULL, *p = NULL;
+			uint32_t port_id;
+
+			/* <port_id>. */
+			port_id = strtoul(token, &token, 0);
+			if (token[0]) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Invalid port ID.";
+				goto error;
+			}
+
+			/* <port_type>. */
+			if (!strcmp(tokens[3], "ethdev"))
+				p = port_in_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "ring"))
+				p = port_in_ring_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "source"))
+				p = port_in_source_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "fd"))
+				p = port_in_fd_parse(&tokens[4], n_tokens - 4, err_msg);
+			else {
+				p = NULL;
+				if (err_msg)
+					*err_msg = "Invalid port type.";
+			}
+
+			if (!p) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			/* New port. */
+			port_type = strdup(tokens[3]);
+			new_id = realloc(s->port_in_id,
+					 (s->n_ports_in + 1) * sizeof(uint32_t));
+			new_type = realloc(s->port_in_type,
+					   (s->n_ports_in + 1) * sizeof(char *));
+			new_params = realloc(s->port_in_params,
+					     (s->n_ports_in + 1) * sizeof(void *));
+			if (!port_type || !new_id || !new_type || !new_params) {
+				uintptr_t pt = (uintptr_t)port_type;
+
+				port_in_params_free(p, tokens[3]);
+				free((void *)pt);
+				free(new_id);
+				free(new_type);
+				free(new_params);
+
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Memory allocation failed.";
+				goto error;
+			}
+
+			s->port_in_id = new_id;
+			s->port_in_type = new_type;
+			s->port_in_params = new_params;
+
+			s->port_in_id[s->n_ports_in] = port_id;
+			s->port_in_type[s->n_ports_in] = port_type;
+			s->port_in_params[s->n_ports_in] = p;
+			s->n_ports_in++;
+
+			continue;
+		}
+
+		/* port out. */
+		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "out")) {
+			char *token = tokens[2];
+			uint32_t *new_id = NULL;
+			const char **new_type = NULL, *port_type = NULL;
+			void **new_params = NULL, *p = NULL;
+			uint32_t port_id;
+
+			/* <port_id>. */
+			port_id = strtoul(token, &token, 0);
+			if (token[0]) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Invalid port ID.";
+				goto error;
+			}
+
+			/* <port_type>. */
+			if (!strcmp(tokens[3], "ethdev"))
+				p = port_out_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "ring"))
+				p = port_out_ring_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "sink"))
+				p = port_out_sink_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "fd"))
+				p = port_out_fd_parse(&tokens[4], n_tokens - 4, err_msg);
+			else {
+				p = NULL;
+				if (err_msg)
+					*err_msg = "Invalid port type.";
+			}
+
+			if (!p) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			/* New port. */
+			port_type = strdup(tokens[3]);
+			new_id = realloc(s->port_out_id,
+					 (s->n_ports_out + 1) * sizeof(uint32_t));
+			new_type = realloc(s->port_out_type,
+					   (s->n_ports_out + 1) * sizeof(char *));
+			new_params = realloc(s->port_out_params,
+					     (s->n_ports_out + 1) * sizeof(void *));
+			if (!port_type || !new_id || !new_type || !new_params) {
+				uintptr_t pt = (uintptr_t)port_type;
+
+				port_out_params_free(p, tokens[3]);
+				free((void *)pt);
+				free(new_id);
+				free(new_type);
+				free(new_params);
+
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Memory allocation failed.";
+				goto error;
+			}
+
+			s->port_out_id = new_id;
+			s->port_out_type = new_type;
+			s->port_out_params = new_params;
+
+			s->port_out_id[s->n_ports_out] = port_id;
+			s->port_out_type[s->n_ports_out] = port_type;
+			s->port_out_params[s->n_ports_out] = p;
+			s->n_ports_out++;
+
+			continue;
+		}
+
+		/* Anything else. */
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Unknown I/O statement.";
+		goto error;
+	}
+
+	return s;
+
+error:
+	pipeline_iospec_free(s);
+
+	return NULL;
+}
+
+int
+pipeline_iospec_configure(struct rte_swx_pipeline *p,
+			  struct pipeline_iospec *s,
+			  const char **err_msg)
+{
+	uint32_t i;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!p || !s) {
+		if (err_msg)
+			*err_msg = "Invalid input argument";
+		return -EINVAL;
+	}
+
+	/* Mirroring. */
+	status = rte_swx_pipeline_mirroring_config(p, &s->mirroring_params);
+	if (status) {
+		if (err_msg)
+			*err_msg = "Pipeline mirroring configuration error.";
+		return status;
+	}
+
+	/* Input ports. */
+	for (i = 0; i < s->n_ports_in; i++) {
+		status = rte_swx_pipeline_port_in_config(p,
+							 i,
+							 s->port_in_type[i],
+							 s->port_in_params[i]);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline input port configuration error.";
+			return status;
+		}
+	}
+
+	/* Output ports. */
+	for (i = 0; i < s->n_ports_out; i++) {
+		status = rte_swx_pipeline_port_out_config(p,
+							  i,
+							  s->port_out_type[i],
+							  s->port_out_params[i]);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline output port configuration error.";
+			return status;
+		}
+	}
+
+	return 0;
+}
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 707b99ba09..62ac4ecfc4 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -1,6 +1,13 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright(c) 2022 Intel Corporation
  */
+#ifndef __INCLUDE_RTE_SWX_PIPELINE_SPEC_H__
+#define __INCLUDE_RTE_SWX_PIPELINE_SPEC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <stdint.h>
 #include <stdio.h>
 
@@ -204,6 +211,38 @@ struct pipeline_spec {
 	uint32_t n_apply;
 };
 
+/*
+ * Mirroring:
+ *      mirroring slots <n_slots> sessions <n_sessions>
+ *
+ * Input ports:
+ *      port in <port_id> ethdev <ethdev_name> rxq <queue_id> bsz <burst_size>
+ *      port in <port_id> ring <ring_name> bsz <burst_size>
+ *      port in <port_id> source mempool <mempool_name> file <file_name> loop <n_loops>
+ *                               packets <n_pkts_max>
+ *      port in <port_id> fd <file_descriptor> mtu <mtu> mempool <mempool_name> bsz <burst_size>
+ *
+ * Output ports:
+ *      port out <port_id> ethdev <ethdev_name> txq <queue_id> bsz <burst_size>
+ *      port out <port_id> ring <ring_name> bsz <burst_size>
+ *      port out <port_id> sink file <file_name> | none
+ *      port out <port_id> fd <file_descriptor> bsz <burst_size>
+ */
+struct pipeline_iospec {
+	struct rte_swx_pipeline_mirroring_params mirroring_params;
+
+	uint32_t *port_in_id;
+	const char **port_in_type;
+	void **port_in_params;
+
+	uint32_t *port_out_id;
+	const char **port_out_type;
+	void **port_out_params;
+
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+};
+
 void
 pipeline_spec_free(struct pipeline_spec *s);
 
@@ -220,3 +259,22 @@ int
 pipeline_spec_configure(struct rte_swx_pipeline *p,
 			struct pipeline_spec *s,
 			const char **err_msg);
+
+void
+pipeline_iospec_free(struct pipeline_iospec *s);
+
+struct pipeline_iospec *
+pipeline_iospec_parse(FILE *spec,
+		      uint32_t *err_line,
+		      const char **err_msg);
+
+int
+pipeline_iospec_configure(struct rte_swx_pipeline *p,
+			  struct pipeline_iospec *s,
+			  const char **err_msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 07/17] pipeline: add API for pipeline code generation
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (4 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
                           ` (10 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the C code generation for the pipeline was hidden under
the hood; now, we make this an explicit API operation. Besides the
functions for the pipeline actions and the pipeline instructions,
the generated C source code now includes the pipeline specification
structure required for the pipeline configuration operations.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline.c | 94 +++++++++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline.h | 25 +++++++++
 lib/pipeline/version.map        |  1 +
 3 files changed, 120 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index c8ccded4f8..dd5f7107fa 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -20,6 +20,7 @@
 #include <rte_swx_table_wm.h>
 
 #include "rte_swx_pipeline_internal.h"
+#include "rte_swx_pipeline_spec.h"
 
 #define CHECK(condition, err_code)                                             \
 do {                                                                           \
@@ -13581,3 +13582,96 @@ pipeline_compile(struct rte_swx_pipeline *p)
 
 	return status;
 }
+
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg)
+
+{
+	struct rte_swx_pipeline *p = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!spec_file || !code_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	status = rte_swx_pipeline_config(&p, NULL, 0);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline configuration error.";
+		goto free;
+	}
+
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto free;
+	}
+
+	/*
+	 * Pipeline code generation.
+	 */
+
+	/* Instruction Group List (IGL) computation: the pipeline configuration must be done first,
+	 * but there is no need for the pipeline build to be done as well.
+	 */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
+		goto free;
+	}
+
+	/* Header file inclusion. */
+	fprintf(code_file, "#include \"rte_swx_pipeline_internal.h\"\n");
+	fprintf(code_file, "#include \"rte_swx_pipeline_spec.h\"\n\n");
+
+	/* Code generation for the pipeline specification. */
+	pipeline_spec_codegen(code_file, s);
+	fprintf(code_file, "\n");
+
+	/* Code generation for the action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		fprintf(code_file, "/**\n * Action %s\n */\n\n", a->name);
+
+		action_data_codegen(a, code_file);
+		fprintf(code_file, "\n");
+
+		action_instr_codegen(a, code_file);
+		fprintf(code_file, "\n");
+	}
+
+	/* Code generation for the pipeline instructions. */
+	instruction_group_list_codegen(igl, p, code_file);
+
+free:
+	instruction_group_list_free(igl);
+	rte_swx_pipeline_free(p);
+	pipeline_spec_free(s);
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index ef50a0fa70..724607b87c 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -957,6 +957,31 @@ __rte_experimental
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p);
 
+/**
+ * Pipeline C code generate based on input specification file
+ *
+ * @param[in] spec_file
+ *   Pipeline specification file (.spec) provided as input.
+ * @param[in] code_file
+ *   Pipeline C language file (.c) to be generated.
+ * @param[out] err_line
+ *   In case of error and non-NULL, the line number within the *spec* file where
+ *   the error occurred. The first line number in the file is 1.
+ * @param[out] err_msg
+ *   In case of error and non-NULL, the error message.
+ * @return
+ *   0 on success or the following error codes otherwise:
+ *   -EINVAL: Invalid argument;
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -EEXIST: Resource with the same name already exists.
+ */
+__rte_experimental
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg);
+
 /**
  * Pipeline build from specification file
  *
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 50029aadcf..8d95005a5b 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -148,5 +148,6 @@ EXPERIMENTAL {
 
 	#added in 22.11
 	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_codegen;
 	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 08/17] pipeline: add API for shared library-based pipeline build
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (5 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
                           ` (9 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the pipeline build operation was done based on the
specification file (typically produced by the P4 compiler), then the C
code with optimized functions for the pipeline actions and
instructions was generated, built into a shared object library, loaded
and installed into the pipeline in a completely hardcoded and
non-customizable way.

Now, this process is split into three explicit stages:
i) code generation (specification file -> C file);
ii) code build (C file -> shared object library);
iii) code installation (library load into the pipeline).

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c              |  85 ++++---
 lib/pipeline/rte_swx_pipeline.c      | 319 +++++++++++----------------
 lib/pipeline/rte_swx_pipeline.h      |  38 ++--
 lib/pipeline/rte_swx_pipeline_spec.c |  51 -----
 lib/pipeline/version.map             |   2 +-
 5 files changed, 208 insertions(+), 287 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index ad553f19ab..f0285675b3 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -984,55 +984,88 @@ cmd_pipeline_port_out(char **tokens,
 }
 
 static const char cmd_pipeline_build_help[] =
-"pipeline <pipeline_name> build <spec_file>\n";
+"pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
 static void
 cmd_pipeline_build(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p = NULL;
-	FILE *spec = NULL;
-	uint32_t err_line;
-	const char *err_msg;
-	int status;
+	struct rte_swx_pipeline *p = NULL;
+	struct rte_swx_ctl_pipeline *ctl = NULL;
+	char *pipeline_name, *lib_file_name, *iospec_file_name;
+	FILE *iospec_file = NULL;
+	uint32_t numa_node = 0;
+	int status = 0;
 
-	if (n_tokens != 4) {
+	/* Parsing. */
+	if (n_tokens != 9) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "build")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "build");
 		return;
 	}
 
-	spec = fopen(tokens[3], "r");
-	if (!spec) {
-		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
+	if (strcmp(tokens[3], "lib")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "lib");
 		return;
 	}
 
-	status = rte_swx_pipeline_build_from_spec(p->p,
-		spec,
-		&err_line,
-		&err_msg);
-	fclose(spec);
-	if (status) {
-		snprintf(out, out_size, "Error %d at line %u: %s\n.",
-			status, err_line, err_msg);
+	lib_file_name = tokens[4];
+
+	if (strcmp(tokens[5], "io")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "io");
 		return;
 	}
 
-	p->ctl = rte_swx_ctl_pipeline_create(p->p);
-	if (!p->ctl) {
-		snprintf(out, out_size, "Pipeline control create failed.");
-		rte_swx_pipeline_free(p->p);
+	iospec_file_name = tokens[6];
+
+	if (strcmp(tokens[7], "numa")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa");
 		return;
 	}
+
+	if (parser_read_uint32(&numa_node, tokens[8])) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "numa_node");
+		return;
+	}
+
+	/* I/O spec file open. */
+	iospec_file = fopen(iospec_file_name, "r");
+	if (!iospec_file) {
+		snprintf(out, out_size, "Cannot open file \"%s\".\n", iospec_file_name);
+		return;
+	}
+
+	status = rte_swx_pipeline_build_from_lib(&p,
+						 pipeline_name,
+						 lib_file_name,
+						 iospec_file,
+						 (int)numa_node);
+	if (status) {
+		snprintf(out, out_size, "Pipeline build failed (%d).", status);
+		goto free;
+	}
+
+	ctl = rte_swx_ctl_pipeline_create(p);
+	if (!ctl) {
+		snprintf(out, out_size, "Pipeline control create failed.");
+		goto free;
+	}
+
+free:
+	if (status)
+		rte_swx_pipeline_free(p);
+
+	if (iospec_file)
+		fclose(iospec_file);
 }
 
 static void
diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index dd5f7107fa..12e156b00b 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -9911,9 +9911,6 @@ rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p,
 	return 0;
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p);
-
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 {
@@ -10003,8 +10000,6 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 
 	p->build_done = 1;
 
-	pipeline_compile(p);
-
 	return 0;
 
 error:
@@ -13327,160 +13322,6 @@ instruction_group_list_custom_instructions_count(struct instruction_group_list *
 	return n_custom_instr;
 }
 
-static int
-pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	FILE *f = NULL;
-
-	/* Create the .c file. */
-	f = fopen("/tmp/pipeline.c", "w");
-	if (!f)
-		return -EIO;
-
-	/* Include the .h file. */
-	fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n");
-
-	/* Add the code for each action. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		fprintf(f, "/**\n * Action %s\n */\n\n", a->name);
-
-		action_data_codegen(a, f);
-
-		fprintf(f, "\n");
-
-		action_instr_codegen(a, f);
-
-		fprintf(f, "\n");
-	}
-
-	/* Add the pipeline code. */
-	instruction_group_list_codegen(igl, p, f);
-
-	/* Close the .c file. */
-	fclose(f);
-
-	return 0;
-}
-
-#ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE
-#define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096
-#endif
-
-static int
-pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	struct instruction_group *g;
-	char *dir_in, *buffer = NULL;
-	const char *dir_out;
-	int status = 0;
-
-	/* Get the environment variables. */
-	dir_in = getenv("RTE_INSTALL_DIR");
-	if (!dir_in) {
-		status = -EINVAL;
-		goto free;
-	}
-
-	dir_out = "/tmp";
-
-	/* Memory allocation for the command buffer. */
-	buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE);
-	if (!buffer) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c "
-		 "-I %s/lib/pipeline "
-		 "-I %s/lib/eal/include "
-		 "-I %s/lib/eal/x86/include "
-		 "-I %s/lib/eal/include/generic "
-		 "-I %s/lib/meter "
-		 "-I %s/lib/port "
-		 "-I %s/lib/table "
-		 "-I %s/lib/pipeline "
-		 "-I %s/config "
-		 "-I %s/build "
-		 "-I %s/lib/eal/linux/include "
-		 ">%s/pipeline.log 2>&1 "
-		 "&& "
-		 "gcc -shared %s/pipeline.o -o %s/libpipeline.so "
-		 ">>%s/pipeline.log 2>&1",
-		 dir_out,
-		 dir_out,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_out,
-		 dir_out,
-		 dir_out,
-		 dir_out);
-
-	/* Build the shared object library. */
-	status = system(buffer);
-	if (status)
-		goto free;
-
-	/* Open library. */
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "%s/libpipeline.so",
-		 dir_out);
-
-	p->lib = dlopen(buffer, RTLD_LAZY);
-	if (!p->lib) {
-		status = -EIO;
-		goto free;
-	}
-
-	/* Get the action function symbols. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name);
-
-		p->action_funcs[a->id] = dlsym(p->lib, buffer);
-		if (!p->action_funcs[a->id]) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-	/* Get the pipeline function symbols. */
-	TAILQ_FOREACH(g, igl, node) {
-		if (g->first_instr_id == g->last_instr_id)
-			continue;
-
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id);
-
-		g->func = dlsym(p->lib, buffer);
-		if (!g->func) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-free:
-	if (status && p->lib) {
-		dlclose(p->lib);
-		p->lib = NULL;
-	}
-
-	free(buffer);
-
-	return status;
-}
-
 static int
 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused,
 		      struct instruction_group_list *igl)
@@ -13548,41 +13389,6 @@ pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
 	instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions);
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p)
-{
-	struct instruction_group_list *igl = NULL;
-	int status = 0;
-
-	igl = instruction_group_list_create(p);
-	if (!igl) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	/* Code generation. */
-	status = pipeline_codegen(p, igl);
-	if (status)
-		goto free;
-
-	/* Build and load the shared object library. */
-	status = pipeline_libload(p, igl);
-	if (status)
-		goto free;
-
-	/* Adjust instructions. */
-	status = pipeline_adjust_check(p, igl);
-	if (status)
-		goto free;
-
-	pipeline_adjust(p, igl);
-
-free:
-	instruction_group_list_free(igl);
-
-	return status;
-}
-
 int
 rte_swx_pipeline_codegen(FILE *spec_file,
 			 FILE *code_file,
@@ -13675,3 +13481,128 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 
 	return status;
 }
+
+int
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline **pipeline,
+				const char *name,
+				const char *lib_file_name,
+				FILE *iospec_file,
+				int numa_node)
+{
+	struct rte_swx_pipeline *p = NULL;
+	void *lib = NULL;
+	struct pipeline_iospec *sio = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	struct instruction_group *g;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!pipeline ||
+	    !name ||
+	    !name[0] ||
+	    !lib_file_name ||
+	    !lib_file_name[0] ||
+	    !iospec_file) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Open the library. */
+	lib = dlopen(lib_file_name, RTLD_LAZY);
+	if (!lib) {
+		status = -EIO;
+		goto free;
+	}
+
+	/* Get the pipeline specification structures. */
+	s = dlsym(lib, "pipeline_spec");
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	sio = pipeline_iospec_parse(iospec_file, NULL, NULL);
+	if (!sio) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration based on the specification structures. */
+	status = rte_swx_pipeline_config(&p, name, numa_node);
+	if (status)
+		goto free;
+
+	status = pipeline_iospec_configure(p, sio, NULL);
+	if (status)
+		goto free;
+
+	status = pipeline_spec_configure(p, s, NULL);
+	if (status)
+		goto free;
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status)
+		goto free;
+
+	/* Action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		snprintf(name, sizeof(name), "action_%s_run", a->name);
+
+		p->action_funcs[a->id] = dlsym(lib, name);
+		if (!p->action_funcs[a->id]) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	/* Pipeline instructions. */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		status = -ENOMEM;
+		goto free;
+	}
+
+	TAILQ_FOREACH(g, igl, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		if (g->first_instr_id == g->last_instr_id)
+			continue;
+
+		snprintf(name, sizeof(name), "pipeline_func_%u", g->group_id);
+
+		g->func = dlsym(lib, name);
+		if (!g->func) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	status = pipeline_adjust_check(p, igl);
+	if (status)
+		goto free;
+
+	pipeline_adjust(p, igl);
+
+	p->lib = lib;
+
+	*pipeline = p;
+
+free:
+	instruction_group_list_free(igl);
+
+	pipeline_iospec_free(sio);
+
+	if (status) {
+		rte_swx_pipeline_free(p);
+
+		if (lib)
+			dlclose(lib);
+	}
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index 724607b87c..9c629d4118 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -983,30 +983,38 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 			 const char **err_msg);
 
 /**
- * Pipeline build from specification file
+ * Pipeline build from shared object library
  *
- * @param[in] p
- *   Pipeline handle.
- * @param[in] spec
- *   Pipeline specification file.
- * @param[out] err_line
- *   In case of error and non-NULL, the line number within the *spec* file where
- *   the error occurred. The first line number in the file is 1.
- * @param[out] err_msg
- *   In case of error and non-NULL, the error message.
+ * The shared object library must be built from the C language source code file
+ * previously generated by the rte_swx_pipeline_codegen() API function.
+ *
+ * The pipeline I/O specification file defines the I/O ports of the pipeline.
+ *
+ * @param[out] p
+ *   Pipeline handle. Must point to valid memory. Contains valid pipeline handle
+ *   when the function returns successfully.
+ * @param[in] name
+ *   Pipeline unique name.
+ * @param[in] lib_file_name
+ *   Shared object library file name.
+ * @param[in] iospec_file
+ *   Pipeline I/O specification file.
+ * @param[in] numa_node
+ *   Non-Uniform Memory Access (NUMA) node.
  * @return
  *   0 on success or the following error codes otherwise:
  *   -EINVAL: Invalid argument;
  *   -ENOMEM: Not enough space/cannot allocate memory;
- *   -EEXIST: Resource with the same name already exists;
+ *   -EEXIST: Pipeline with this name already exists;
  *   -ENODEV: Extern object or table creation error.
  */
 __rte_experimental
 int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg);
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline **p,
+				const char *name,
+				const char *lib_file_name,
+				FILE *iospec_file,
+				int numa_node);
 
 /**
  * Pipeline run
diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index f34803793d..3c16daf7de 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -3522,57 +3522,6 @@ pipeline_spec_configure(struct rte_swx_pipeline *p,
 	return 0;
 }
 
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec_file,
-				 uint32_t *err_line,
-				 const char **err_msg)
-{
-	struct pipeline_spec *s = NULL;
-	int status = 0;
-
-	/* Check the input arguments. */
-	if (!p || !spec_file) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Invalid input argument.";
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Spec file parse. */
-	s = pipeline_spec_parse(spec_file, err_line, err_msg);
-	if (!s) {
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Pipeline configure. */
-	status = pipeline_spec_configure(p, s, err_msg);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		goto error;
-	}
-
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
-
-error:
-	pipeline_spec_free(s);
-	return status;
-}
-
 static void
 port_in_params_free(void *params, const char *port_type)
 {
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 8d95005a5b..16806e6802 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -82,7 +82,6 @@ EXPERIMENTAL {
 	rte_swx_ctl_table_ops_get;
 	rte_swx_pipeline_action_config;
 	rte_swx_pipeline_build;
-	rte_swx_pipeline_build_from_spec;
 	rte_swx_pipeline_config;
 	rte_swx_pipeline_extern_func_register;
 	rte_swx_pipeline_extern_object_config;
@@ -148,6 +147,7 @@ EXPERIMENTAL {
 
 	#added in 22.11
 	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_build_from_lib;
 	rte_swx_pipeline_codegen;
 	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 09/17] examples/pipeline: add CLI command for pipeline code generation
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (6 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
                           ` (8 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the pipeline code generation operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 61 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index f0285675b3..2b38977be1 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -983,6 +983,53 @@ cmd_pipeline_port_out(char **tokens,
 	}
 }
 
+static const char cmd_pipeline_codegen_help[] =
+"pipeline codegen <spec_file> <code_file>\n";
+
+static void
+cmd_pipeline_codegen(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	FILE *spec_file = NULL;
+	FILE *code_file = NULL;
+	uint32_t err_line;
+	const char *err_msg;
+	int status;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	spec_file = fopen(tokens[2], "r");
+	if (!spec_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[2]);
+		return;
+	}
+
+	code_file = fopen(tokens[3], "w");
+	if (!code_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
+		return;
+	}
+
+	status = rte_swx_pipeline_codegen(spec_file,
+					  code_file,
+					  &err_line,
+					  &err_msg);
+
+	fclose(spec_file);
+	fclose(code_file);
+
+	if (status) {
+		snprintf(out, out_size, "Error %d at line %u: %s\n.",
+			status, err_line, err_msg);
+		return;
+	}
+}
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
@@ -3009,6 +3056,7 @@ cmd_help(char **tokens,
 			"\tpipeline create\n"
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
+			"\tpipeline codegen\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3078,6 +3126,12 @@ cmd_help(char **tokens,
 		}
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3356,6 +3410,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "codegen") == 0)) {
+			cmd_pipeline_codegen(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 10/17] examples/pipeline: add CLI command for shared library build
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (7 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
                           ` (7 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the shared object library build operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 157 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 153 insertions(+), 4 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 2b38977be1..28cf8d4178 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -6,6 +6,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_ethdev.h>
@@ -25,6 +26,10 @@
 #define CMD_MAX_TOKENS     256
 #endif
 
+#ifndef MAX_LINE_SIZE
+#define MAX_LINE_SIZE 2048
+#endif
+
 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
@@ -1030,6 +1035,140 @@ cmd_pipeline_codegen(char **tokens,
 		return;
 	}
 }
+
+static const char cmd_pipeline_libbuild_help[] =
+"pipeline libbuild <code_file> <lib_file>\n";
+
+static void
+cmd_pipeline_libbuild(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	char *code_file, *lib_file, *obj_file = NULL, *log_file = NULL;
+	char *install_dir, *cwd = NULL, *buffer = NULL;
+	size_t length;
+	int status = 0;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		goto free;
+	}
+
+	install_dir = getenv("RTE_INSTALL_DIR");
+	if (!install_dir) {
+		cwd = malloc(MAX_LINE_SIZE);
+		if (!cwd) {
+			snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+			goto free;
+		}
+
+		install_dir = getcwd(cwd, MAX_LINE_SIZE);
+		if (!install_dir) {
+			snprintf(out, out_size, "Error: Path too long.\n");
+			goto free;
+		}
+	}
+
+	snprintf(out, out_size, "Using DPDK source code from \"%s\".\n", install_dir);
+	out_size -= strlen(out);
+	out += strlen(out);
+
+	code_file = tokens[2];
+	length = strnlen(code_file, MAX_LINE_SIZE);
+	if ((length < 3) ||
+	    (code_file[length - 2] != '.') ||
+	    (code_file[length - 1] != 'c')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "code_file");
+		goto free;
+	}
+
+	lib_file = tokens[3];
+	length = strnlen(lib_file, MAX_LINE_SIZE);
+	if ((length < 4) ||
+	    (lib_file[length - 3] != '.') ||
+	    (lib_file[length - 2] != 's') ||
+	    (lib_file[length - 1] != 'o')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "lib_file");
+		goto free;
+	}
+
+	obj_file = malloc(length);
+	log_file = malloc(length + 2);
+	if (!obj_file || !log_file) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		goto free;
+	}
+
+	memcpy(obj_file, lib_file, length - 2);
+	obj_file[length - 2] = 'o';
+	obj_file[length - 1] = 0;
+
+	memcpy(log_file, lib_file, length - 2);
+	log_file[length - 2] = 'l';
+	log_file[length - 1] = 'o';
+	log_file[length] = 'g';
+	log_file[length + 1] = 0;
+
+	buffer = malloc(MAX_LINE_SIZE);
+	if (!buffer) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		return;
+	}
+
+	snprintf(buffer,
+		 MAX_LINE_SIZE,
+		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s %s "
+		 "-I %s/lib/pipeline "
+		 "-I %s/lib/eal/include "
+		 "-I %s/lib/eal/x86/include "
+		 "-I %s/lib/eal/include/generic "
+		 "-I %s/lib/meter "
+		 "-I %s/lib/port "
+		 "-I %s/lib/table "
+		 "-I %s/lib/pipeline "
+		 "-I %s/config "
+		 "-I %s/build "
+		 "-I %s/lib/eal/linux/include "
+		 ">%s 2>&1 "
+		 "&& "
+		 "gcc -shared %s -o %s "
+		 ">>%s 2>&1",
+		 obj_file,
+		 code_file,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 log_file,
+		 obj_file,
+		 lib_file,
+		 log_file);
+
+	status = system(buffer);
+	if (status) {
+		snprintf(out,
+			 out_size,
+			 "Library build failed, see file \"%s\" for details.\n",
+			 log_file);
+		goto free;
+	}
+
+free:
+	free(cwd);
+	free(obj_file);
+	free(log_file);
+	free(buffer);
+}
+
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
@@ -1127,10 +1266,6 @@ table_entry_free(struct rte_swx_table_entry *entry)
 	free(entry);
 }
 
-#ifndef MAX_LINE_SIZE
-#define MAX_LINE_SIZE 2048
-#endif
-
 static int
 pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p,
 			   const char *table_name,
@@ -3057,6 +3192,7 @@ cmd_help(char **tokens,
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
+			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3132,6 +3268,12 @@ cmd_help(char **tokens,
 		return;
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "libbuild") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_libbuild_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3417,6 +3559,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "libbuild") == 0)) {
+			cmd_pipeline_libbuild(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 11/17] examples/pipeline: remove the obsolete pipeline create CLI command
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (8 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
                           ` (6 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline configuration is now done through the I/O specification
file, hence this CLI command is no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 47 -----------------------------------------
 1 file changed, 47 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 28cf8d4178..7b725a9c27 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -523,39 +523,6 @@ cmd_tap(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_create_help[] =
-"pipeline <pipeline_name> create <numa_node>\n";
-
-static void
-cmd_pipeline_create(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	char *name;
-	uint32_t numa_node;
-
-	if (n_tokens != 4) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	name = tokens[1];
-
-	if (parser_read_uint32(&numa_node, tokens[3]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "numa_node");
-		return;
-	}
-
-	p = pipeline_create(obj, name, (int)numa_node);
-	if (!p) {
-		snprintf(out, out_size, "pipeline create error.");
-		return;
-	}
-}
-
 static const char cmd_pipeline_port_in_help[] =
 "pipeline <pipeline_name> port in <port_id>\n"
 "   link <link_name> rxq <queue_id> bsz <burst_size>\n"
@@ -3188,7 +3155,6 @@ cmd_help(char **tokens,
 			"\tmempool\n"
 			"\tlink\n"
 			"\ttap\n"
-			"\tpipeline create\n"
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
@@ -3241,12 +3207,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if ((strcmp(tokens[0], "pipeline") == 0) &&
-		(n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
-		snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
-		return;
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
 		if (strcmp(tokens[2], "in") == 0) {
@@ -3529,13 +3489,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 	}
 
 	if (strcmp(tokens[0], "pipeline") == 0) {
-		if ((n_tokens >= 3) &&
-			(strcmp(tokens[2], "create") == 0)) {
-			cmd_pipeline_create(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
 		if ((n_tokens >= 4) &&
 			(strcmp(tokens[2], "port") == 0) &&
 			(strcmp(tokens[3], "in") == 0)) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 12/17] examples/pipeline: remove the obsolete port configuration CLI commands
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (9 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
                           ` (5 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline I/O ports configuration is now done through the I/O
specification file, hence these CLI commands are no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 465 ----------------------------------------
 1 file changed, 465 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 7b725a9c27..b26e73c706 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -523,438 +523,6 @@ cmd_tap(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_port_in_help[] =
-"pipeline <pipeline_name> port in <port_id>\n"
-"   link <link_name> rxq <queue_id> bsz <burst_size>\n"
-"   ring <ring_name> bsz <burst_size>\n"
-"   | source <mempool_name> <file_name> loop <n_loops>\n"
-"   | tap <tap_name> mempool <mempool_name> mtu <mtu> bsz <burst_size>\n";
-
-static void
-cmd_pipeline_port_in(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	int status;
-	uint32_t port_id = 0, t0;
-
-	if (n_tokens < 6) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[2], "port") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
-		return;
-	}
-
-	if (strcmp(tokens[3], "in") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
-		return;
-	}
-
-	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-		return;
-	}
-
-	t0 = 5;
-
-	if (strcmp(tokens[t0], "link") == 0) {
-		struct rte_swx_port_ethdev_reader_params params;
-		struct link *link;
-
-		if (n_tokens < t0 + 6) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in link");
-			return;
-		}
-
-		link = link_find(obj, tokens[t0 + 1]);
-		if (!link) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"link_name");
-			return;
-		}
-		params.dev_name = link->dev_name;
-
-		if (strcmp(tokens[t0 + 2], "rxq") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
-			return;
-		}
-
-		if (parser_read_uint16(&params.queue_id, tokens[t0 + 3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"queue_id");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 4], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 5])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 6;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"ethdev",
-			&params);
-	} else if (strcmp(tokens[t0], "ring") == 0) {
-		struct rte_swx_port_ring_reader_params params;
-		struct ring *ring;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in ring");
-			return;
-		}
-
-		ring = ring_find(obj, tokens[t0 + 1]);
-		if (!ring) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"ring_name");
-			return;
-		}
-		params.name = ring->name;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"ring",
-			&params);
-	} else if (strcmp(tokens[t0], "source") == 0) {
-		struct rte_swx_port_source_params params;
-		struct mempool *mp;
-
-		if (n_tokens < t0 + 5) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in source");
-			return;
-		}
-
-		mp = mempool_find(obj, tokens[t0 + 1]);
-		if (!mp) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"mempool_name");
-			return;
-		}
-		params.pool = mp->m;
-
-		params.file_name = tokens[t0 + 2];
-
-		if (strcmp(tokens[t0 + 3], "loop") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "loop");
-			return;
-		}
-
-		if (parser_read_uint64(&params.n_loops, tokens[t0 + 4])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"n_loops");
-			return;
-		}
-
-		t0 += 5;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"source",
-			&params);
-	} else if (strcmp(tokens[t0], "tap") == 0) {
-		struct rte_swx_port_fd_reader_params params;
-		struct tap *tap;
-		struct mempool *mp;
-
-		if (n_tokens < t0 + 8) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in tap");
-			return;
-		}
-
-		tap = tap_find(obj, tokens[t0 + 1]);
-		if (!tap) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"tap_name");
-			return;
-		}
-		params.fd = tap->fd;
-
-		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
-				"mempool");
-			return;
-		}
-
-		mp = mempool_find(obj, tokens[t0 + 3]);
-		if (!mp) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"mempool_name");
-			return;
-		}
-		params.mempool = mp->m;
-
-		if (strcmp(tokens[t0 + 4], "mtu") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
-				"mtu");
-			return;
-		}
-
-		if (parser_read_uint32(&params.mtu, tokens[t0 + 5]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 6], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 7])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 8;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"fd",
-			&params);
-
-	} else {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (status) {
-		snprintf(out, out_size, "port in error.");
-		return;
-	}
-
-	if (n_tokens != t0) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-}
-
-static const char cmd_pipeline_port_out_help[] =
-"pipeline <pipeline_name> port out <port_id>\n"
-"   link <link_name> txq <txq_id> bsz <burst_size>\n"
-"   ring <ring_name> bsz <burst_size>\n"
-"   | sink <file_name> | none\n"
-"   | tap <tap_name> bsz <burst_size>\n";
-
-static void
-cmd_pipeline_port_out(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	int status;
-	uint32_t port_id = 0, t0;
-
-	if (n_tokens < 6) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[2], "port") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
-		return;
-	}
-
-	if (strcmp(tokens[3], "out") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
-		return;
-	}
-
-	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-		return;
-	}
-
-	t0 = 5;
-
-	if (strcmp(tokens[t0], "link") == 0) {
-		struct rte_swx_port_ethdev_writer_params params;
-		struct link *link;
-
-		if (n_tokens < t0 + 6) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out link");
-			return;
-		}
-
-		link = link_find(obj, tokens[t0 + 1]);
-		if (!link) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"link_name");
-			return;
-		}
-		params.dev_name = link->dev_name;
-
-		if (strcmp(tokens[t0 + 2], "txq") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
-			return;
-		}
-
-		if (parser_read_uint16(&params.queue_id, tokens[t0 + 3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"queue_id");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 4], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 5])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 6;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"ethdev",
-			&params);
-	} else if (strcmp(tokens[t0], "ring") == 0) {
-		struct rte_swx_port_ring_writer_params params;
-		struct ring *ring;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out link");
-			return;
-		}
-
-		ring = ring_find(obj, tokens[t0 + 1]);
-		if (!ring) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"ring_name");
-			return;
-		}
-		params.name = ring->name;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"ring",
-			&params);
-	} else if (strcmp(tokens[t0], "sink") == 0) {
-		struct rte_swx_port_sink_params params;
-
-		params.file_name = strcmp(tokens[t0 + 1], "none") ?
-			tokens[t0 + 1] : NULL;
-
-		t0 += 2;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"sink",
-			&params);
-	} else if (strcmp(tokens[t0], "tap") == 0) {
-		struct rte_swx_port_fd_writer_params params;
-		struct tap *tap;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out tap");
-			return;
-		}
-
-		tap = tap_find(obj, tokens[t0 + 1]);
-		if (!tap) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"tap_name");
-			return;
-		}
-		params.fd = tap->fd;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"fd",
-			&params);
-	} else {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (status) {
-		snprintf(out, out_size, "port out error.");
-		return;
-	}
-
-	if (n_tokens != t0) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-}
-
 static const char cmd_pipeline_codegen_help[] =
 "pipeline codegen <spec_file> <code_file>\n";
 
@@ -3155,8 +2723,6 @@ cmd_help(char **tokens,
 			"\tmempool\n"
 			"\tlink\n"
 			"\ttap\n"
-			"\tpipeline port in\n"
-			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
@@ -3207,21 +2773,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if ((strcmp(tokens[0], "pipeline") == 0) &&
-		(n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
-		if (strcmp(tokens[2], "in") == 0) {
-			snprintf(out, out_size, "\n%s\n",
-				cmd_pipeline_port_in_help);
-			return;
-		}
-
-		if (strcmp(tokens[2], "out") == 0) {
-			snprintf(out, out_size, "\n%s\n",
-				cmd_pipeline_port_out_help);
-			return;
-		}
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
@@ -3489,22 +3040,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 	}
 
 	if (strcmp(tokens[0], "pipeline") == 0) {
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "port") == 0) &&
-			(strcmp(tokens[3], "in") == 0)) {
-			cmd_pipeline_port_in(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "port") == 0) &&
-			(strcmp(tokens[3], "out") == 0)) {
-			cmd_pipeline_port_out(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[1], "codegen") == 0)) {
 			cmd_pipeline_codegen(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (10 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
                           ` (4 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline mirroring configuration is done through the I/O
specification file, so this CLI command is no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 76 -----------------------------------------
 1 file changed, 76 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index b26e73c706..fa828c008b 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -2457,68 +2457,6 @@ cmd_pipeline_stats(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_mirror_help[] =
-"pipeline <pipeline_name> mirror slots <n_slots> sessions <n_sessions>\n";
-
-static void
-cmd_pipeline_mirror(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct rte_swx_pipeline_mirroring_params params;
-	struct pipeline *p;
-	int status;
-
-	if (n_tokens != 7) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[0], "pipeline")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
-		return;
-	}
-
-	if (strcmp(tokens[2], "mirror")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror");
-		return;
-	}
-
-	if (strcmp(tokens[3], "slots")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "slots");
-		return;
-	}
-
-	if (parser_read_uint32(&params.n_slots, tokens[4])) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "n_slots");
-		return;
-	}
-
-	if (strcmp(tokens[5], "sessions")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "sessions");
-		return;
-	}
-
-	if (parser_read_uint32(&params.n_sessions, tokens[6])) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "n_sessions");
-		return;
-	}
-
-	status = rte_swx_pipeline_mirroring_config(p->p, &params);
-	if (status) {
-		snprintf(out, out_size, "Command failed!\n");
-		return;
-	}
-}
-
 static const char cmd_pipeline_mirror_session_help[] =
 "pipeline <pipeline_name> mirror session <session_id> port <port_id> clone fast | slow "
 "truncate <truncation_length>\n";
@@ -2746,7 +2684,6 @@ cmd_help(char **tokens,
 			"\tpipeline meter set\n"
 			"\tpipeline meter stats\n"
 			"\tpipeline stats\n"
-			"\tpipeline mirror\n"
 			"\tpipeline mirror session\n"
 			"\tthread pipeline enable\n"
 			"\tthread pipeline disable\n\n");
@@ -2958,12 +2895,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (!strcmp(tokens[0], "pipeline") &&
-		(n_tokens == 2) && !strcmp(tokens[1], "mirror")) {
-		snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_help);
-		return;
-	}
-
 	if (!strcmp(tokens[0], "pipeline") &&
 		(n_tokens == 3) && !strcmp(tokens[1], "mirror")
 		&& !strcmp(tokens[2], "session")) {
@@ -3217,13 +3148,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "mirror") == 0) &&
-			(strcmp(tokens[3], "slots") == 0)) {
-			cmd_pipeline_mirror(tokens, n_tokens, out, out_size, obj);
-			return;
-		}
-
 		if ((n_tokens >= 4) &&
 			(strcmp(tokens[2], "mirror") == 0) &&
 			(strcmp(tokens[3], "session") == 0)) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 14/17] examples/pipeline: use the pipeline name query API
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (11 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
                           ` (3 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Convert the CLI commands to use the pipeline name query API and remove
the linked list of pipeline objects previously maintained by the
application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c    | 268 ++++++++++++++++++++-----------------
 examples/pipeline/obj.c    |  67 ----------
 examples/pipeline/obj.h    |  24 ----
 examples/pipeline/thread.c |  65 ++++-----
 examples/pipeline/thread.h |   9 +-
 5 files changed, 175 insertions(+), 258 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index fa828c008b..f48ff326be 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -858,9 +858,9 @@ cmd_pipeline_table_add(char **tokens,
 		       uint32_t n_tokens,
 		       char *out,
 		       size_t out_size,
-		       void *obj)
+		       void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -872,8 +872,8 @@ cmd_pipeline_table_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -887,7 +887,7 @@ cmd_pipeline_table_add(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_entries_add(p->ctl,
+	status = pipeline_table_entries_add(ctl,
 					    table_name,
 					    file,
 					    &file_line_number);
@@ -956,9 +956,9 @@ cmd_pipeline_table_delete(char **tokens,
 			  uint32_t n_tokens,
 			  char *out,
 			  size_t out_size,
-			  void *obj)
+			  void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -970,8 +970,8 @@ cmd_pipeline_table_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -985,7 +985,7 @@ cmd_pipeline_table_delete(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_entries_delete(p->ctl,
+	status = pipeline_table_entries_delete(ctl,
 					       table_name,
 					       file,
 					       &file_line_number);
@@ -1054,9 +1054,9 @@ cmd_pipeline_table_default(char **tokens,
 			   uint32_t n_tokens,
 			   char *out,
 			   size_t out_size,
-			   void *obj)
+			   void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1068,8 +1068,8 @@ cmd_pipeline_table_default(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1083,7 +1083,7 @@ cmd_pipeline_table_default(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_default_entry_add(p->ctl,
+	status = pipeline_table_default_entry_add(ctl,
 						  table_name,
 						  file,
 						  &file_line_number);
@@ -1103,9 +1103,9 @@ cmd_pipeline_table_show(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name;
 	FILE *file = NULL;
 	int status;
@@ -1116,8 +1116,8 @@ cmd_pipeline_table_show(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1129,7 +1129,7 @@ cmd_pipeline_table_show(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_table_fprintf(file, p->ctl, table_name);
+	status = rte_swx_ctl_pipeline_table_fprintf(file, ctl, table_name);
 	if (status)
 		snprintf(out, out_size, MSG_ARG_INVALID, "table_name");
 
@@ -1145,9 +1145,9 @@ cmd_pipeline_selector_group_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	uint32_t group_id;
 	int status;
@@ -1158,8 +1158,8 @@ cmd_pipeline_selector_group_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1177,7 +1177,7 @@ cmd_pipeline_selector_group_add(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_group_add(p->ctl,
+	status = rte_swx_ctl_pipeline_selector_group_add(ctl,
 		selector_name,
 		&group_id);
 	if (status)
@@ -1194,9 +1194,9 @@ cmd_pipeline_selector_group_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	uint32_t group_id;
 	int status;
@@ -1207,8 +1207,8 @@ cmd_pipeline_selector_group_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1231,7 +1231,7 @@ cmd_pipeline_selector_group_delete(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_group_delete(p->ctl,
+	status = rte_swx_ctl_pipeline_selector_group_delete(ctl,
 		selector_name,
 		group_id);
 	if (status)
@@ -1402,9 +1402,9 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1416,8 +1416,8 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1443,7 +1443,7 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 		return;
 	}
 
-	status = pipeline_selector_group_members_add(p->ctl,
+	status = pipeline_selector_group_members_add(ctl,
 					    selector_name,
 					    file,
 					    &file_line_number);
@@ -1512,9 +1512,9 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1526,8 +1526,8 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1553,7 +1553,7 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 		return;
 	}
 
-	status = pipeline_selector_group_members_delete(p->ctl,
+	status = pipeline_selector_group_members_delete(ctl,
 					    selector_name,
 					    file,
 					    &file_line_number);
@@ -1573,9 +1573,9 @@ cmd_pipeline_selector_show(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	FILE *file = NULL;
 	int status;
@@ -1586,8 +1586,8 @@ cmd_pipeline_selector_show(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1600,7 +1600,7 @@ cmd_pipeline_selector_show(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_fprintf(file, p->ctl, selector_name);
+	status = rte_swx_ctl_pipeline_selector_fprintf(file, ctl, selector_name);
 	if (status)
 		snprintf(out, out_size, MSG_ARG_INVALID, "selector_name");
 
@@ -1665,9 +1665,9 @@ cmd_pipeline_learner_default(char **tokens,
 			     uint32_t n_tokens,
 			     char *out,
 			     size_t out_size,
-			     void *obj)
+			     void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *learner_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1679,8 +1679,8 @@ cmd_pipeline_learner_default(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1694,7 +1694,7 @@ cmd_pipeline_learner_default(char **tokens,
 		return;
 	}
 
-	status = pipeline_learner_default_entry_add(p->ctl,
+	status = pipeline_learner_default_entry_add(ctl,
 						    learner_name,
 						    file,
 						    &file_line_number);
@@ -1714,9 +1714,9 @@ cmd_pipeline_commit(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name;
 	int status;
 
@@ -1726,13 +1726,13 @@ cmd_pipeline_commit(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_commit(p->ctl, 1);
+	status = rte_swx_ctl_pipeline_commit(ctl, 1);
 	if (status)
 		snprintf(out, out_size, "Commit failed. "
 			"Use \"commit\" to retry or \"abort\" to discard the pending work.\n");
@@ -1746,9 +1746,9 @@ cmd_pipeline_abort(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name;
 
 	if (n_tokens != 3) {
@@ -1757,13 +1757,13 @@ cmd_pipeline_abort(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
 
-	rte_swx_ctl_pipeline_abort(p->ctl);
+	rte_swx_ctl_pipeline_abort(ctl);
 }
 
 static const char cmd_pipeline_regrd_help[] =
@@ -1774,9 +1774,9 @@ cmd_pipeline_regrd(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint64_t value;
 	uint32_t idx;
@@ -1787,8 +1787,8 @@ cmd_pipeline_regrd(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1805,7 +1805,7 @@ cmd_pipeline_regrd(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value);
+	status = rte_swx_ctl_pipeline_regarray_read(p, name, idx, &value);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1822,9 +1822,9 @@ cmd_pipeline_regwr(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint64_t value;
 	uint32_t idx;
@@ -1835,8 +1835,8 @@ cmd_pipeline_regwr(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1858,7 +1858,7 @@ cmd_pipeline_regwr(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value);
+	status = rte_swx_ctl_pipeline_regarray_write(p, name, idx, value);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1874,10 +1874,10 @@ cmd_pipeline_meter_profile_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_meter_trtcm_params params;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *profile_name;
 	int status;
 
@@ -1886,8 +1886,8 @@ cmd_pipeline_meter_profile_add(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1949,7 +1949,7 @@ cmd_pipeline_meter_profile_add(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_meter_profile_add(p->p, profile_name, &params);
+	status = rte_swx_ctl_meter_profile_add(p, profile_name, &params);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1964,9 +1964,9 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *profile_name;
 	int status;
 
@@ -1975,8 +1975,8 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1998,7 +1998,7 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_meter_profile_delete(p->p, profile_name);
+	status = rte_swx_ctl_meter_profile_delete(p, profile_name);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -2014,9 +2014,9 @@ cmd_pipeline_meter_reset(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2025,8 +2025,8 @@ cmd_pipeline_meter_reset(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2066,7 +2066,7 @@ cmd_pipeline_meter_reset(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_reset(p->p, name, idx0);
+		status = rte_swx_ctl_meter_reset(p, name, idx0);
 		if (status) {
 			snprintf(out, out_size, "Command failed for index %u.\n", idx0);
 			return;
@@ -2083,9 +2083,9 @@ cmd_pipeline_meter_set(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name, *profile_name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2094,8 +2094,8 @@ cmd_pipeline_meter_set(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2142,7 +2142,7 @@ cmd_pipeline_meter_set(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name);
+		status = rte_swx_ctl_meter_set(p, name, idx0, profile_name);
 		if (status) {
 			snprintf(out, out_size, "Command failed for index %u.\n", idx0);
 			return;
@@ -2159,10 +2159,10 @@ cmd_pipeline_meter_stats(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_ctl_meter_stats stats;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2171,8 +2171,8 @@ cmd_pipeline_meter_stats(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2235,7 +2235,7 @@ cmd_pipeline_meter_stats(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats);
+		status = rte_swx_ctl_meter_stats_read(p, name, idx0, &stats);
 		if (status) {
 			snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0);
 			out_size -= strlen(out);
@@ -2265,10 +2265,10 @@ cmd_pipeline_stats(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_ctl_pipeline_info info;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	uint32_t i;
 	int status;
 
@@ -2277,8 +2277,8 @@ cmd_pipeline_stats(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2288,7 +2288,7 @@ cmd_pipeline_stats(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_info_get(p->p, &info);
+	status = rte_swx_ctl_pipeline_info_get(p, &info);
 	if (status) {
 		snprintf(out, out_size, "Pipeline info get error.");
 		return;
@@ -2301,7 +2301,7 @@ cmd_pipeline_stats(char **tokens,
 	for (i = 0; i < info.n_ports_in; i++) {
 		struct rte_swx_port_in_stats stats;
 
-		rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats);
+		rte_swx_ctl_pipeline_port_in_stats_read(p, i, &stats);
 
 		snprintf(out, out_size, "\tPort %u:"
 			" packets %" PRIu64
@@ -2319,7 +2319,7 @@ cmd_pipeline_stats(char **tokens,
 	for (i = 0; i < info.n_ports_out; i++) {
 		struct rte_swx_port_out_stats stats;
 
-		rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats);
+		rte_swx_ctl_pipeline_port_out_stats_read(p, i, &stats);
 
 		if (i != info.n_ports_out - 1)
 			snprintf(out, out_size, "\tPort %u:", i);
@@ -2358,13 +2358,13 @@ cmd_pipeline_stats(char **tokens,
 		};
 		uint32_t j;
 
-		status = rte_swx_ctl_table_info_get(p->p, i, &table_info);
+		status = rte_swx_ctl_table_info_get(p, i, &table_info);
 		if (status) {
 			snprintf(out, out_size, "Table info get error.");
 			return;
 		}
 
-		status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats);
+		status = rte_swx_ctl_pipeline_table_stats_read(p, table_info.name, &stats);
 		if (status) {
 			snprintf(out, out_size, "Table stats read error.");
 			return;
@@ -2382,7 +2382,7 @@ cmd_pipeline_stats(char **tokens,
 		for (j = 0; j < info.n_actions; j++) {
 			struct rte_swx_ctl_action_info action_info;
 
-			status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
+			status = rte_swx_ctl_action_info_get(p, j, &action_info);
 			if (status) {
 				snprintf(out, out_size, "Action info get error.");
 				return;
@@ -2410,13 +2410,13 @@ cmd_pipeline_stats(char **tokens,
 		};
 		uint32_t j;
 
-		status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info);
+		status = rte_swx_ctl_learner_info_get(p, i, &learner_info);
 		if (status) {
 			snprintf(out, out_size, "Learner table info get error.");
 			return;
 		}
 
-		status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats);
+		status = rte_swx_ctl_pipeline_learner_stats_read(p, learner_info.name, &stats);
 		if (status) {
 			snprintf(out, out_size, "Learner table stats read error.");
 			return;
@@ -2442,7 +2442,7 @@ cmd_pipeline_stats(char **tokens,
 		for (j = 0; j < info.n_actions; j++) {
 			struct rte_swx_ctl_action_info action_info;
 
-			status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
+			status = rte_swx_ctl_action_info_get(p, j, &action_info);
 			if (status) {
 				snprintf(out, out_size, "Action info get error.");
 				return;
@@ -2466,10 +2466,10 @@ cmd_pipeline_mirror_session(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_pipeline_mirroring_session_params params;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	uint32_t session_id = 0;
 	int status;
 
@@ -2483,8 +2483,8 @@ cmd_pipeline_mirror_session(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2538,7 +2538,7 @@ cmd_pipeline_mirror_session(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_mirroring_session_set(p->p, session_id, &params);
+	status = rte_swx_ctl_pipeline_mirroring_session_set(p, session_id, &params);
 	if (status) {
 		snprintf(out, out_size, "Command failed!\n");
 		return;
@@ -2546,21 +2546,25 @@ cmd_pipeline_mirror_session(char **tokens,
 }
 
 static const char cmd_thread_pipeline_enable_help[] =
-"thread <thread_id> pipeline <pipeline_name> enable\n";
+"thread <thread_id> pipeline <pipeline_name> enable [ period <timer_period_ms> ]\n";
+
+#ifndef TIMER_PERIOD_MS_DEFAULT
+#define TIMER_PERIOD_MS_DEFAULT 10
+#endif
 
 static void
 cmd_thread_pipeline_enable(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	char *pipeline_name;
-	struct pipeline *p;
-	uint32_t thread_id;
+	struct rte_swx_pipeline *p;
+	uint32_t thread_id, timer_period_ms = TIMER_PERIOD_MS_DEFAULT;
 	int status;
 
-	if (n_tokens != 5) {
+	if ((n_tokens != 5) && (n_tokens != 7)) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
@@ -2576,8 +2580,8 @@ cmd_thread_pipeline_enable(char **tokens,
 	}
 
 	pipeline_name = tokens[3];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(pipeline_name);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2587,7 +2591,19 @@ cmd_thread_pipeline_enable(char **tokens,
 		return;
 	}
 
-	status = thread_pipeline_enable(thread_id, obj, pipeline_name);
+	if (n_tokens == 7) {
+		if (strcmp(tokens[5], "period") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
+			return;
+		}
+
+		if (parser_read_uint32(&timer_period_ms, tokens[6]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
+			return;
+		}
+	}
+
+	status = thread_pipeline_enable(thread_id, p, timer_period_ms);
 	if (status) {
 		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
 		return;
@@ -2602,9 +2618,9 @@ cmd_thread_pipeline_disable(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	char *pipeline_name;
 	uint32_t thread_id;
 	int status;
@@ -2625,8 +2641,8 @@ cmd_thread_pipeline_disable(char **tokens,
 	}
 
 	pipeline_name = tokens[3];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(pipeline_name);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2636,7 +2652,7 @@ cmd_thread_pipeline_disable(char **tokens,
 		return;
 	}
 
-	status = thread_pipeline_disable(thread_id, obj, pipeline_name);
+	status = thread_pipeline_disable(thread_id, p);
 	if (status) {
 		snprintf(out, out_size, MSG_CMD_FAIL,
 			"thread pipeline disable");
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index 967342c580..d1f519180e 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -16,7 +16,6 @@
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
-#include <rte_swx_pipeline.h>
 #include <rte_swx_ctl.h>
 
 #include "obj.h"
@@ -41,11 +40,6 @@ TAILQ_HEAD(ring_list, ring);
  */
 TAILQ_HEAD(tap_list, tap);
 
-/*
- * pipeline
- */
-TAILQ_HEAD(pipeline_list, pipeline);
-
 /*
  * obj
  */
@@ -53,7 +47,6 @@ struct obj {
 	struct mempool_list mempool_list;
 	struct link_list link_list;
 	struct ring_list ring_list;
-	struct pipeline_list pipeline_list;
 	struct tap_list tap_list;
 };
 
@@ -513,65 +506,6 @@ tap_create(struct obj *obj, const char *name)
 
 #endif
 
-/*
- * pipeline
- */
-#ifndef PIPELINE_MSGQ_SIZE
-#define PIPELINE_MSGQ_SIZE                                 64
-#endif
-
-struct pipeline *
-pipeline_create(struct obj *obj, const char *name, int numa_node)
-{
-	struct pipeline *pipeline;
-	struct rte_swx_pipeline *p = NULL;
-	int status;
-
-	/* Check input params */
-	if ((name == NULL) ||
-		pipeline_find(obj, name))
-		return NULL;
-
-	/* Resource create */
-	status = rte_swx_pipeline_config(&p, name, numa_node);
-	if (status)
-		goto error;
-
-	/* Node allocation */
-	pipeline = calloc(1, sizeof(struct pipeline));
-	if (pipeline == NULL)
-		goto error;
-
-	/* Node fill in */
-	strlcpy(pipeline->name, name, sizeof(pipeline->name));
-	pipeline->p = p;
-	pipeline->timer_period_ms = 10;
-
-	/* Node add to list */
-	TAILQ_INSERT_TAIL(&obj->pipeline_list, pipeline, node);
-
-	return pipeline;
-
-error:
-	rte_swx_pipeline_free(p);
-	return NULL;
-}
-
-struct pipeline *
-pipeline_find(struct obj *obj, const char *name)
-{
-	struct pipeline *pipeline;
-
-	if (!obj || !name)
-		return NULL;
-
-	TAILQ_FOREACH(pipeline, &obj->pipeline_list, node)
-		if (strcmp(name, pipeline->name) == 0)
-			return pipeline;
-
-	return NULL;
-}
-
 /*
  * obj
  */
@@ -587,7 +521,6 @@ obj_init(void)
 	TAILQ_INIT(&obj->mempool_list);
 	TAILQ_INIT(&obj->link_list);
 	TAILQ_INIT(&obj->ring_list);
-	TAILQ_INIT(&obj->pipeline_list);
 	TAILQ_INIT(&obj->tap_list);
 
 	return obj;
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index b921610554..e63a9c0e9a 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -143,28 +143,4 @@ tap_next(struct obj *obj, struct tap *tap);
 struct tap *
 tap_create(struct obj *obj, const char *name);
 
-/*
- * pipeline
- */
-struct pipeline {
-	TAILQ_ENTRY(pipeline) node;
-	char name[NAME_SIZE];
-
-	struct rte_swx_pipeline *p;
-	struct rte_swx_ctl_pipeline *ctl;
-
-	uint32_t timer_period_ms;
-	int enabled;
-	uint32_t thread_id;
-	uint32_t cpu_id;
-};
-
-struct pipeline *
-pipeline_create(struct obj *obj,
-		const char *name,
-		int numa_node);
-
-struct pipeline *
-pipeline_find(struct obj *obj, const char *name);
-
 #endif /* _INCLUDE_OBJ_H_ */
diff --git a/examples/pipeline/thread.c b/examples/pipeline/thread.c
index 5fe7eae00e..6d15f51fb2 100644
--- a/examples/pipeline/thread.c
+++ b/examples/pipeline/thread.c
@@ -228,20 +228,33 @@ thread_msg_send_recv(uint32_t thread_id,
 	return rsp;
 }
 
+static int
+thread_is_pipeline_enabled(uint32_t thread_id, struct rte_swx_pipeline *p)
+{
+	struct thread *t = &thread[thread_id];
+	struct thread_data *td = &thread_data[thread_id];
+	uint32_t i;
+
+	if (!t->enabled)
+		return 0; /* Pipeline NOT enabled on this thread. */
+
+	for (i = 0; i < td->n_pipelines; i++)
+		if (td->p[i] == p)
+			return 1; /* Pipeline enabled on this thread. */
+
+	return 0 /* Pipeline NOT enabled on this thread. */;
+}
+
 int
-thread_pipeline_enable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name)
+thread_pipeline_enable(uint32_t thread_id, struct rte_swx_pipeline *p, uint32_t timer_period_ms)
 {
-	struct pipeline *p = pipeline_find(obj, pipeline_name);
 	struct thread *t;
 	struct thread_msg_req *req;
 	struct thread_msg_rsp *rsp;
 	int status;
 
 	/* Check input params */
-	if ((thread_id >= RTE_MAX_LCORE) ||
-		(p == NULL))
+	if ((thread_id >= RTE_MAX_LCORE) || !p || !timer_period_ms)
 		return -1;
 
 	t = &thread[thread_id];
@@ -256,19 +269,14 @@ thread_pipeline_enable(uint32_t thread_id,
 			return -1;
 
 		/* Data plane thread */
-		td->p[td->n_pipelines] = p->p;
+		td->p[td->n_pipelines] = p;
 
-		tdp->p = p->p;
-		tdp->timer_period =
-			(rte_get_tsc_hz() * p->timer_period_ms) / 1000;
+		tdp->p = p;
+		tdp->timer_period = (rte_get_tsc_hz() * timer_period_ms) / 1000;
 		tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
 
 		td->n_pipelines++;
 
-		/* Pipeline */
-		p->thread_id = thread_id;
-		p->enabled = 1;
-
 		return 0;
 	}
 
@@ -279,8 +287,8 @@ thread_pipeline_enable(uint32_t thread_id,
 
 	/* Write request */
 	req->type = THREAD_REQ_PIPELINE_ENABLE;
-	req->pipeline_enable.p = p->p;
-	req->pipeline_enable.timer_period_ms = p->timer_period_ms;
+	req->pipeline_enable.p = p;
+	req->pipeline_enable.timer_period_ms = timer_period_ms;
 
 	/* Send request and wait for response */
 	rsp = thread_msg_send_recv(thread_id, req);
@@ -295,38 +303,28 @@ thread_pipeline_enable(uint32_t thread_id,
 	if (status)
 		return status;
 
-	p->thread_id = thread_id;
-	p->enabled = 1;
-
 	return 0;
 }
 
 int
-thread_pipeline_disable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name)
+thread_pipeline_disable(uint32_t thread_id, struct rte_swx_pipeline *p)
 {
-	struct pipeline *p = pipeline_find(obj, pipeline_name);
 	struct thread *t;
 	struct thread_msg_req *req;
 	struct thread_msg_rsp *rsp;
 	int status;
 
 	/* Check input params */
-	if ((thread_id >= RTE_MAX_LCORE) ||
-		(p == NULL))
+	if ((thread_id >= RTE_MAX_LCORE) || !p)
 		return -1;
 
 	t = &thread[thread_id];
 	if (t->enabled == 0)
 		return -1;
 
-	if (p->enabled == 0)
+	if (!thread_is_pipeline_enabled(thread_id, p))
 		return 0;
 
-	if (p->thread_id != thread_id)
-		return -1;
-
 	if (!thread_is_running(thread_id)) {
 		struct thread_data *td = &thread_data[thread_id];
 		uint32_t i;
@@ -334,7 +332,7 @@ thread_pipeline_disable(uint32_t thread_id,
 		for (i = 0; i < td->n_pipelines; i++) {
 			struct pipeline_data *tdp = &td->pipeline_data[i];
 
-			if (tdp->p != p->p)
+			if (tdp->p != p)
 				continue;
 
 			/* Data plane thread */
@@ -350,9 +348,6 @@ thread_pipeline_disable(uint32_t thread_id,
 
 			td->n_pipelines--;
 
-			/* Pipeline */
-			p->enabled = 0;
-
 			break;
 		}
 
@@ -366,7 +361,7 @@ thread_pipeline_disable(uint32_t thread_id,
 
 	/* Write request */
 	req->type = THREAD_REQ_PIPELINE_DISABLE;
-	req->pipeline_disable.p = p->p;
+	req->pipeline_disable.p = p;
 
 	/* Send request and wait for response */
 	rsp = thread_msg_send_recv(thread_id, req);
@@ -381,8 +376,6 @@ thread_pipeline_disable(uint32_t thread_id,
 	if (status)
 		return status;
 
-	p->enabled = 0;
-
 	return 0;
 }
 
diff --git a/examples/pipeline/thread.h b/examples/pipeline/thread.h
index d9d8645d4c..712cb25bbb 100644
--- a/examples/pipeline/thread.h
+++ b/examples/pipeline/thread.h
@@ -7,17 +7,16 @@
 
 #include <stdint.h>
 
-#include "obj.h"
+#include <rte_swx_pipeline.h>
 
 int
 thread_pipeline_enable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name);
+		       struct rte_swx_pipeline *p,
+		       uint32_t timer_period_ms);
 
 int
 thread_pipeline_disable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name);
+			struct rte_swx_pipeline *p);
 
 int
 thread_init(void);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 15/17] examples/pipeline: rework the link CLI command
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (12 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
                           ` (2 subsequent siblings)
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Rework the link CLI command for better alignment with the naming
conventions used in the pipeline I/O specification file. Use the
library linked list of devices and remove the application list.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 81 +++++++++++++----------------------------
 examples/pipeline/obj.c | 16 ++------
 examples/pipeline/obj.h |  4 --
 3 files changed, 29 insertions(+), 72 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index f48ff326be..d56a830fb7 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -106,22 +106,6 @@ parser_read_uint32(uint32_t *value, const char *p)
 	return 0;
 }
 
-static int
-parser_read_uint16(uint16_t *value, const char *p)
-{
-	uint64_t val = 0;
-	int ret = parser_read_uint64(&val, p);
-
-	if (ret < 0)
-		return ret;
-
-	if (val > UINT16_MAX)
-		return -ERANGE;
-
-	*value = val;
-	return 0;
-}
-
 #define PARSE_DELIMITER " \f\n\r\t\v"
 
 static int
@@ -230,16 +214,15 @@ cmd_mempool(char **tokens,
 	}
 }
 
-static const char cmd_link_help[] =
-"link <link_name>\n"
-"   dev <device_name> | port <port_id>\n"
+static const char cmd_ethdev_help[] =
+"ethdev <ethdev_name>\n"
 "   rxq <n_queues> <queue_size> <mempool_name>\n"
 "   txq <n_queues> <queue_size>\n"
 "   promiscuous on | off\n"
 "   [rss <qid_0> ... <qid_n>]\n";
 
 static void
-cmd_link(char **tokens,
+cmd_ethdev(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
@@ -252,65 +235,51 @@ cmd_link(char **tokens,
 
 	memset(&p, 0, sizeof(p));
 
-	if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
+	if ((n_tokens < 11) || (n_tokens > 12 + LINK_RXQ_RSS_MAX)) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
 	name = tokens[1];
 
-	if (strcmp(tokens[2], "dev") == 0)
-		p.dev_name = tokens[3];
-	else if (strcmp(tokens[2], "port") == 0) {
-		p.dev_name = NULL;
-
-		if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-			return;
-		}
-	} else {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
-		return;
-	}
-
-	if (strcmp(tokens[4], "rxq") != 0) {
+	if (strcmp(tokens[2], "rxq") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
 		return;
 	}
 
-	if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
+	if (parser_read_uint32(&p.rx.n_queues, tokens[3]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
 		return;
 	}
-	if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
+	if (parser_read_uint32(&p.rx.queue_size, tokens[4]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
 		return;
 	}
 
-	p.rx.mempool_name = tokens[7];
+	p.rx.mempool_name = tokens[5];
 
-	if (strcmp(tokens[8], "txq") != 0) {
+	if (strcmp(tokens[6], "txq") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
 		return;
 	}
 
-	if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
+	if (parser_read_uint32(&p.tx.n_queues, tokens[7]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
 		return;
 	}
 
-	if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
+	if (parser_read_uint32(&p.tx.queue_size, tokens[8]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
 		return;
 	}
 
-	if (strcmp(tokens[11], "promiscuous") != 0) {
+	if (strcmp(tokens[9], "promiscuous") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
 		return;
 	}
 
-	if (strcmp(tokens[12], "on") == 0)
+	if (strcmp(tokens[10], "on") == 0)
 		p.promiscuous = 1;
-	else if (strcmp(tokens[12], "off") == 0)
+	else if (strcmp(tokens[10], "off") == 0)
 		p.promiscuous = 0;
 	else {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
@@ -319,10 +288,10 @@ cmd_link(char **tokens,
 
 	/* RSS */
 	p.rx.rss = NULL;
-	if (n_tokens > 13) {
+	if (n_tokens > 11) {
 		uint32_t queue_id, i;
 
-		if (strcmp(tokens[13], "rss") != 0) {
+		if (strcmp(tokens[11], "rss") != 0) {
 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
 			return;
 		}
@@ -330,7 +299,7 @@ cmd_link(char **tokens,
 		p.rx.rss = &rss;
 
 		rss.n_queues = 0;
-		for (i = 14; i < n_tokens; i++) {
+		for (i = 12; i < n_tokens; i++) {
 			if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
 				snprintf(out, out_size, MSG_ARG_INVALID,
 					"queue_id");
@@ -406,10 +375,10 @@ print_link_info(struct link *link, char *out, size_t out_size)
 }
 
 /*
- * link show [<link_name>]
+ * ethdev show [<ethdev_name>]
  */
 static void
-cmd_link_show(char **tokens,
+cmd_ethdev_show(char **tokens,
 	      uint32_t n_tokens,
 	      char *out,
 	      size_t out_size,
@@ -2675,7 +2644,7 @@ cmd_help(char **tokens,
 			"Type 'help <command>' for command details.\n\n"
 			"List of commands:\n"
 			"\tmempool\n"
-			"\tlink\n"
+			"\tethdev\n"
 			"\ttap\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
@@ -2711,8 +2680,8 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (strcmp(tokens[0], "link") == 0) {
-		snprintf(out, out_size, "\n%s\n", cmd_link_help);
+	if (strcmp(tokens[0], "ethdev") == 0) {
+		snprintf(out, out_size, "\n%s\n", cmd_ethdev_help);
 		return;
 	}
 
@@ -2966,13 +2935,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 		return;
 	}
 
-	if (strcmp(tokens[0], "link") == 0) {
+	if (strcmp(tokens[0], "ethdev") == 0) {
 		if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) {
-			cmd_link_show(tokens, n_tokens, out, out_size, obj);
+			cmd_ethdev_show(tokens, n_tokens, out, out_size, obj);
 			return;
 		}
 
-		cmd_link(tokens, n_tokens, out, out_size, obj);
+		cmd_ethdev(tokens, n_tokens, out, out_size, obj);
 		return;
 	}
 
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index d1f519180e..950ab831fb 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -181,7 +181,7 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 	struct mempool *mempool;
 	uint32_t cpu_id, i;
 	int status;
-	uint16_t port_id;
+	uint16_t port_id = 0;
 
 	/* Check input params */
 	if ((name == NULL) ||
@@ -193,16 +193,9 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 		(params->tx.queue_size == 0))
 		return NULL;
 
-	port_id = params->port_id;
-	if (params->dev_name) {
-		status = rte_eth_dev_get_port_by_name(params->dev_name,
-			&port_id);
-
-		if (status)
-			return NULL;
-	} else
-		if (!rte_eth_dev_is_valid_port(port_id))
-			return NULL;
+	status = rte_eth_dev_get_port_by_name(name, &port_id);
+	if (status)
+		return NULL;
 
 	if (rte_eth_dev_info_get(port_id, &port_info) != 0)
 		return NULL;
@@ -315,7 +308,6 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 	/* Node fill in */
 	strlcpy(link->name, name, sizeof(link->name));
 	link->port_id = port_id;
-	rte_eth_dev_get_name_by_port(port_id, link->dev_name);
 	link->n_rxq = params->rx.n_queues;
 	link->n_txq = params->tx.n_queues;
 
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index e63a9c0e9a..af270a8e57 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -63,9 +63,6 @@ struct link_params_rss {
 };
 
 struct link_params {
-	const char *dev_name;
-	uint16_t port_id; /**< Valid only when *dev_name* is NULL. */
-
 	struct {
 		uint32_t n_queues;
 		uint32_t queue_size;
@@ -84,7 +81,6 @@ struct link_params {
 struct link {
 	TAILQ_ENTRY(link) node;
 	char name[NAME_SIZE];
-	char dev_name[NAME_SIZE];
 	uint16_t port_id;
 	uint32_t n_rxq;
 	uint32_t n_txq;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 16/17] examples/pipelines: remove obsolete tap CLI command
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (13 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-27 23:01         ` [PATCH V5 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
  2022-07-28  8:22         ` [PATCH V5 01/17] pipeline: add pipeline name Bruce Richardson
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Remove the tap CLI command, as the file descriptor I/O ports of the
pipeline are now configured trough the I/O specification file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 37 -----------------
 examples/pipeline/obj.c | 89 -----------------------------------------
 examples/pipeline/obj.h | 18 ---------
 3 files changed, 144 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index d56a830fb7..75c32b9089 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -466,32 +466,6 @@ cmd_ring(char **tokens,
 	}
 }
 
-static const char cmd_tap_help[] =
-"tap <tap_name>\n";
-
-static void
-cmd_tap(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct tap *tap;
-	char *name;
-
-	if (n_tokens < 2) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-	name = tokens[1];
-
-	tap = tap_create(obj, name);
-	if (tap == NULL) {
-		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
-		return;
-	}
-}
-
 static const char cmd_pipeline_codegen_help[] =
 "pipeline codegen <spec_file> <code_file>\n";
 
@@ -2645,7 +2619,6 @@ cmd_help(char **tokens,
 			"List of commands:\n"
 			"\tmempool\n"
 			"\tethdev\n"
-			"\ttap\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
@@ -2690,11 +2663,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (strcmp(tokens[0], "tap") == 0) {
-		snprintf(out, out_size, "\n%s\n", cmd_tap_help);
-		return;
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
@@ -2950,11 +2918,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 		return;
 	}
 
-	if (strcmp(tokens[0], "tap") == 0) {
-		cmd_tap(tokens, n_tokens, out, out_size, obj);
-		return;
-	}
-
 	if (strcmp(tokens[0], "pipeline") == 0) {
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[1], "codegen") == 0)) {
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index 950ab831fb..b7e2316eec 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -35,11 +35,6 @@ TAILQ_HEAD(link_list, link);
  */
 TAILQ_HEAD(ring_list, ring);
 
-/*
- * tap
- */
-TAILQ_HEAD(tap_list, tap);
-
 /*
  * obj
  */
@@ -47,7 +42,6 @@ struct obj {
 	struct mempool_list mempool_list;
 	struct link_list link_list;
 	struct ring_list ring_list;
-	struct tap_list tap_list;
 };
 
 /*
@@ -416,88 +410,6 @@ ring_find(struct obj *obj, const char *name)
 	return NULL;
 }
 
-/*
- * tap
- */
-#define TAP_DEV		"/dev/net/tun"
-
-struct tap *
-tap_find(struct obj *obj, const char *name)
-{
-	struct tap *tap;
-
-	if (!obj || !name)
-		return NULL;
-
-	TAILQ_FOREACH(tap, &obj->tap_list, node)
-		if (strcmp(tap->name, name) == 0)
-			return tap;
-
-	return NULL;
-}
-
-struct tap *
-tap_next(struct obj *obj, struct tap *tap)
-{
-	return (tap == NULL) ?
-		TAILQ_FIRST(&obj->tap_list) : TAILQ_NEXT(tap, node);
-}
-
-#ifndef RTE_EXEC_ENV_LINUX
-
-struct tap *
-tap_create(struct obj *obj __rte_unused, const char *name __rte_unused)
-{
-	return NULL;
-}
-
-#else
-
-struct tap *
-tap_create(struct obj *obj, const char *name)
-{
-	struct tap *tap;
-	struct ifreq ifr;
-	int fd, status;
-
-	/* Check input params */
-	if ((name == NULL) ||
-		tap_find(obj, name))
-		return NULL;
-
-	/* Resource create */
-	fd = open(TAP_DEV, O_RDWR | O_NONBLOCK);
-	if (fd < 0)
-		return NULL;
-
-	memset(&ifr, 0, sizeof(ifr));
-	ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
-	strlcpy(ifr.ifr_name, name, IFNAMSIZ);
-
-	status = ioctl(fd, TUNSETIFF, (void *) &ifr);
-	if (status < 0) {
-		close(fd);
-		return NULL;
-	}
-
-	/* Node allocation */
-	tap = calloc(1, sizeof(struct tap));
-	if (tap == NULL) {
-		close(fd);
-		return NULL;
-	}
-	/* Node fill in */
-	strlcpy(tap->name, name, sizeof(tap->name));
-	tap->fd = fd;
-
-	/* Node add to list */
-	TAILQ_INSERT_TAIL(&obj->tap_list, tap, node);
-
-	return tap;
-}
-
-#endif
-
 /*
  * obj
  */
@@ -513,7 +425,6 @@ obj_init(void)
 	TAILQ_INIT(&obj->mempool_list);
 	TAILQ_INIT(&obj->link_list);
 	TAILQ_INIT(&obj->ring_list);
-	TAILQ_INIT(&obj->tap_list);
 
 	return obj;
 }
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index af270a8e57..8ea1c414c2 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -121,22 +121,4 @@ ring_create(struct obj *obj,
 struct ring *
 ring_find(struct obj *obj, const char *name);
 
-/*
- * tap
- */
-struct tap {
-	TAILQ_ENTRY(tap) node;
-	char name[NAME_SIZE];
-	int fd;
-};
-
-struct tap *
-tap_find(struct obj *obj, const char *name);
-
-struct tap *
-tap_next(struct obj *obj, struct tap *tap);
-
-struct tap *
-tap_create(struct obj *obj, const char *name);
-
 #endif /* _INCLUDE_OBJ_H_ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V5 17/17] examples/pipeline: call the code generation and build CLI commands
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (14 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
@ 2022-07-27 23:01         ` Cristian Dumitrescu
  2022-07-28  8:22         ` [PATCH V5 01/17] pipeline: add pipeline name Bruce Richardson
  16 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-27 23:01 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Update the example CLI scripts with the commands for code generation
and shared object library build.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/examples/ethdev.io          | 27 +++++++++
 examples/pipeline/examples/fib.cli            | 44 +++++++-------
 examples/pipeline/examples/hash_func.cli      | 41 ++++++-------
 examples/pipeline/examples/l2fwd.cli          | 44 ++++++++------
 examples/pipeline/examples/l2fwd_macswp.cli   | 44 ++++++++------
 .../pipeline/examples/l2fwd_macswp_pcap.cli   | 35 +++++++----
 examples/pipeline/examples/l2fwd_pcap.cli     | 35 +++++++----
 examples/pipeline/examples/learner.cli        | 43 +++++++-------
 examples/pipeline/examples/meter.cli          | 58 +++++++++++--------
 examples/pipeline/examples/mirroring.cli      | 46 ++++++++-------
 examples/pipeline/examples/pcap.io            | 27 +++++++++
 examples/pipeline/examples/recirculation.cli  | 41 ++++++-------
 examples/pipeline/examples/registers.cli      | 53 +++++++++--------
 examples/pipeline/examples/selector.cli       | 55 +++++++++++-------
 examples/pipeline/examples/varbit.cli         | 41 ++++++-------
 examples/pipeline/examples/vxlan.cli          | 48 ++++++++++-----
 examples/pipeline/examples/vxlan_pcap.cli     | 39 +++++++++----
 17 files changed, 444 insertions(+), 277 deletions(-)
 create mode 100644 examples/pipeline/examples/ethdev.io
 create mode 100644 examples/pipeline/examples/pcap.io

diff --git a/examples/pipeline/examples/ethdev.io b/examples/pipeline/examples/ethdev.io
new file mode 100644
index 0000000000..cf2f3e20bd
--- /dev/null
+++ b/examples/pipeline/examples/ethdev.io
@@ -0,0 +1,27 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2022 Intel Corporation
+
+;
+; Pipeline packet mirroring.
+;
+mirroring slots 4 sessions 64
+
+;
+; Pipeline input ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port in 0 ethdev 0000:18:00.0 rxq 0 bsz 32
+port in 1 ethdev 0000:18:00.1 rxq 0 bsz 32
+port in 2 ethdev 0000:3b:00.0 rxq 0 bsz 32
+port in 3 ethdev 0000:3b:00.1 rxq 0 bsz 32
+
+;
+; Pipeline output ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port out 0 ethdev 0000:18:00.0 txq 0 bsz 32
+port out 1 ethdev 0000:18:00.1 txq 0 bsz 32
+port out 2 ethdev 0000:3b:00.0 txq 0 bsz 32
+port out 3 ethdev 0000:3b:00.1 txq 0 bsz 32
diff --git a/examples/pipeline/examples/fib.cli b/examples/pipeline/examples/fib.cli
index 93ab2b08f8..4e30c1320f 100644
--- a/examples/pipeline/examples/fib.cli
+++ b/examples/pipeline/examples/fib.cli
@@ -1,38 +1,38 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/fib.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/fib.spec /tmp/fib.c
+pipeline libbuild /tmp/fib.c /tmp/fib.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/fib.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/fib.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Initial set of table entries.
 ;
-; The table entries can later be updated at run-time through the CLI commands. Once the application
-; has been successfully started, the command to get the CLI prompt is: telnet 0.0.0.0 8086.
+; The table entries can later be updated at run-time through the CLI commands.
 ;
 pipeline PIPELINE0 table routing_table add ./examples/pipeline/examples/fib_routing_table.txt
 pipeline PIPELINE0 selector nexthop_group_table group add
diff --git a/examples/pipeline/examples/hash_func.cli b/examples/pipeline/examples/hash_func.cli
index d65cd62d17..b2e219e4c9 100644
--- a/examples/pipeline/examples/hash_func.cli
+++ b/examples/pipeline/examples/hash_func.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/hash_func.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/hash_func.spec /tmp/hash_func.c
+pipeline libbuild /tmp/hash_func.c /tmp/hash_func.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/hash_func.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/hash_func.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/l2fwd.cli b/examples/pipeline/examples/l2fwd.cli
index d89caf2d0a..27e37021b9 100644
--- a/examples/pipeline/examples/l2fwd.cli
+++ b/examples/pipeline/examples/l2fwd.cli
@@ -1,25 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd.so io ./examples/pipeline/examples/ethdev.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp.cli b/examples/pipeline/examples/l2fwd_macswp.cli
index 0f2a89ac5b..11bb4543b9 100644
--- a/examples/pipeline/examples/l2fwd_macswp.cli
+++ b/examples/pipeline/examples/l2fwd_macswp.cli
@@ -1,25 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_macswp.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd_macswp.so io ./examples/pipeline/examples/ethdev.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp_pcap.cli b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
index e9656fe3c2..8724dae3b0 100644
--- a/examples/pipeline/examples/l2fwd_macswp_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
@@ -1,20 +1,31 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-pipeline PIPELINE0 create 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_macswp_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd_macswp.so io ./examples/pipeline/examples/pcap.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_pcap.cli b/examples/pipeline/examples/l2fwd_pcap.cli
index 23fcb199f1..4db0a0dc56 100644
--- a/examples/pipeline/examples/l2fwd_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_pcap.cli
@@ -1,20 +1,31 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-pipeline PIPELINE0 create 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd.so io ./examples/pipeline/examples/pcap.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/learner.cli b/examples/pipeline/examples/learner.cli
index 688ce34f34..6c8aa3921e 100644
--- a/examples/pipeline/examples/learner.cli
+++ b/examples/pipeline/examples/learner.cli
@@ -1,36 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/learner.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/learner.spec /tmp/learner.c
+pipeline libbuild /tmp/learner.c /tmp/learner.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/learner.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/learner.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
 ;
 thread 1 pipeline PIPELINE0 enable
-
-; Once the application has started, the command to get the CLI prompt is: telnet 0.0.0.0 8086
diff --git a/examples/pipeline/examples/meter.cli b/examples/pipeline/examples/meter.cli
index b29ed24022..c1b88c882a 100644
--- a/examples/pipeline/examples/meter.cli
+++ b/examples/pipeline/examples/meter.cli
@@ -1,31 +1,43 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-; Example command line:
-;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/meter.cli
-
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/meter.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/meter.spec /tmp/meter.c
+pipeline libbuild /tmp/meter.c /tmp/meter.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/meter.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/meter.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 meter profile platinum add cir 46000000 pir 138000000 cbs 1000000 pbs 1000000
 pipeline PIPELINE0 meter meters from 0 to 15 set profile platinum
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/mirroring.cli b/examples/pipeline/examples/mirroring.cli
index 46d57db4ec..1d439e04d3 100644
--- a/examples/pipeline/examples/mirroring.cli
+++ b/examples/pipeline/examples/mirroring.cli
@@ -1,36 +1,38 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/mirroring.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/mirroring.spec /tmp/mirroring.c
+pipeline libbuild /tmp/mirroring.c /tmp/mirroring.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-pipeline PIPELINE0 mirror slots 4 sessions 16
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/mirroring.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/mirroring.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
-; Packet mirroring sessions.
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
 ;
 pipeline PIPELINE0 mirror session 0 port 1 clone fast truncate 0
 pipeline PIPELINE0 mirror session 1 port 2 clone slow truncate 0
diff --git a/examples/pipeline/examples/pcap.io b/examples/pipeline/examples/pcap.io
new file mode 100644
index 0000000000..111f61afae
--- /dev/null
+++ b/examples/pipeline/examples/pcap.io
@@ -0,0 +1,27 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2022 Intel Corporation
+
+;
+; Pipeline packet mirroring.
+;
+mirroring slots 4 sessions 64
+
+;
+; Pipeline input ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port in 0 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 1 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 2 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 3 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+
+;
+; Pipeline output ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port out 0 sink file none
+port out 1 sink file none
+port out 2 sink file none
+port out 3 sink file none
diff --git a/examples/pipeline/examples/recirculation.cli b/examples/pipeline/examples/recirculation.cli
index f855c5c327..52d0894f12 100644
--- a/examples/pipeline/examples/recirculation.cli
+++ b/examples/pipeline/examples/recirculation.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/recirculation.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/recirculation.spec /tmp/recirculation.c
+pipeline libbuild /tmp/recirculation.c /tmp/recirculation.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/recirculation.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/recirculation.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/registers.cli b/examples/pipeline/examples/registers.cli
index 8d026294cb..3516f76a5b 100644
--- a/examples/pipeline/examples/registers.cli
+++ b/examples/pipeline/examples/registers.cli
@@ -1,28 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-; Example command line:
-;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/registers.cli
-
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/registers.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/registers.spec /tmp/registers.c
+pipeline libbuild /tmp/registers.c /tmp/registers.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/registers.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/registers.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/selector.cli b/examples/pipeline/examples/selector.cli
index 123782c57b..f0e251b657 100644
--- a/examples/pipeline/examples/selector.cli
+++ b/examples/pipeline/examples/selector.cli
@@ -1,30 +1,45 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/selector.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/selector.spec /tmp/selector.c
+pipeline libbuild /tmp/selector.c /tmp/selector.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/selector.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/selector.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 selector s group add
 pipeline PIPELINE0 selector s group member add ./examples/pipeline/examples/selector.txt
 pipeline PIPELINE0 commit
 pipeline PIPELINE0 selector s show
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/varbit.cli b/examples/pipeline/examples/varbit.cli
index 9caeb9ca26..0f89990471 100644
--- a/examples/pipeline/examples/varbit.cli
+++ b/examples/pipeline/examples/varbit.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/varbit.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/varbit.spec /tmp/varbit.c
+pipeline libbuild /tmp/varbit.c /tmp/varbit.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/varbit.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/varbit.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/vxlan.cli b/examples/pipeline/examples/vxlan.cli
index 444f3f7bd8..1fbd1be6e4 100644
--- a/examples/pipeline/examples/vxlan.cli
+++ b/examples/pipeline/examples/vxlan.cli
@@ -1,27 +1,43 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/vxlan.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/vxlan.so io ./examples/pipeline/examples/ethdev.io numa 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/vxlan_pcap.cli b/examples/pipeline/examples/vxlan_pcap.cli
index 83fca8d0d9..adc7f73312 100644
--- a/examples/pipeline/examples/vxlan_pcap.cli
+++ b/examples/pipeline/examples/vxlan_pcap.cli
@@ -1,22 +1,39 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/vxlan_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/vxlan.so io ./examples/pipeline/examples/pcap.io numa 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* Re: [PATCH V5 01/17] pipeline: add pipeline name
  2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
                           ` (15 preceding siblings ...)
  2022-07-27 23:01         ` [PATCH V5 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
@ 2022-07-28  8:22         ` Bruce Richardson
  2022-07-28 15:17           ` Dumitrescu, Cristian
  16 siblings, 1 reply; 90+ messages in thread
From: Bruce Richardson @ 2022-07-28  8:22 UTC (permalink / raw)
  To: Cristian Dumitrescu; +Cc: dev, Kamalakannan R .

On Wed, Jul 27, 2022 at 11:01:16PM +0000, Cristian Dumitrescu wrote:
> Add an unique name to every pipeline. This enables the library to
> maintain a list of the existing pipeline objects, which can be
> queried by the application.
> 
> Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
> ---
I really think this patchset could do with a cover letter. Since you are
now on v5, it would be nice to have a cover-letter where the differences
between each of the patch versions are called out. A cover-letter is also
nice to outline the overall scope of the changes rather than asking
reviewers to go through the set patch by patch to see what is in there.

Thanks,
/Bruce

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH V6 00/17] pipeline: pipeline configuration and build improvements
  2022-07-18 13:07 [PATCH 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
                   ` (8 preceding siblings ...)
  2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
@ 2022-07-28 15:11 ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 01/17] pipeline: add pipeline name Cristian Dumitrescu
                     ` (17 more replies)
  9 siblings, 18 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev

The sequence of steps to build a SWX pipeline object are:

1. Create the specification file (pipeline.p4 -> pipeline.spec): This text file represents the
   pipeline program that is typically generated by the P4 compiler or sometimes manually created.

2. Generate the C source code file (pipeline.spec -> pipeline.c): The C file contains a C function
   for every pipeline action and several C functions for the pipeline main program. It allows the C
   compiler to generate optimized code by having access to the entire pipeline program rather than
   using the small pre-build functions corresponding to the individual instructions

3. Build the shared object library (pipeline.c -> pipeline.o -> pipeline.so).

4. Load the shared object library (pipeline.so): At initialization, the pipeline object is “patched”
   with the optimized C functions from the shared object library.

Previously, steps 2., 3. and 4. were implemented under the hood by the pipeline library at the
initialization time in a completely hard-coded and non-customizable way. The user was not able to
select the C compiler (GCC was assumed), the compiler version, the build flags, the file locations,
etc. The code generation (step 2.) and library build (step 3.) were done on-the-fly at init and
could potentially fail for many setup related reasons.

Now, this process is no longer done under the hood by the pipeline library and the individual steps
are explicitly supported by the API functions. The code generation (step 2.) is done off-line at any
time before the pipeline execution. The library build (step 3.) is also done off-line and is now
fully customizable by the user, who is able to gracefully access the generated C code and decide on
the various build options.

We also take the opportunity to streamline the pipeline I/O port configuration by introducing an I/O
specification file. Essentially, the pipeline is now configured and build based on two files:

a) The shared object library file (pipeline.so): It defines how the packets are processed by the
   program through tables and actions; the same P4 program can be executed by many pipelines.

b) The I/O specification file (pipeline.io): High level text file defining how the packets are
   received and transmitted by the pipeline; this is not part of the P4 program, which is completely
   agnostic about the pipeline I/O ports. This is defined differently for each pipeline object when
   initialized.

Change log:

V6:
-Added the cover letter. No code changes.

V5:
-Fixed more style issues reported by the CI/CD.

V4:
-Fixed style issues reported by the CI/CD.

V3:
-Added support for the pipeline I/O specification file.

V2:
-Fixed style issues reported by the CI/CD.

Cristian Dumitrescu (17):
  pipeline: add pipeline name
  pipeline: move specification data structures to internal header
  pipeline: add pipeline specification data structure
  pipeline: rework the specification file-based pipeline build
  pipeline: generate the code for pipeline specification structure
  pipeline: add support for pipeline I/O specification
  pipeline: add API for pipeline code generation
  pipeline: add API for shared library-based pipeline build
  examples/pipeline: add CLI command for pipeline code generation
  examples/pipeline: add CLI command for shared library build
  examples/pipeline: remove the obsolete pipeline create CLI command
  examples/pipeline: remove the obsolete port configuration CLI commands
  examples/pipeline: remove the obsolete mirroring configuration CLI
    command
  examples/pipeline: use the pipeline name query API
  examples/pipeline: rework the link CLI command
  examples/pipelines: remove obsolete tap CLI command
  examples/pipeline: call the code generation and build CLI commands

 examples/pipeline/cli.c                       | 1133 +++------
 examples/pipeline/examples/ethdev.io          |   27 +
 examples/pipeline/examples/fib.cli            |   44 +-
 examples/pipeline/examples/hash_func.cli      |   41 +-
 examples/pipeline/examples/l2fwd.cli          |   44 +-
 examples/pipeline/examples/l2fwd_macswp.cli   |   44 +-
 .../pipeline/examples/l2fwd_macswp_pcap.cli   |   35 +-
 examples/pipeline/examples/l2fwd_pcap.cli     |   35 +-
 examples/pipeline/examples/learner.cli        |   43 +-
 examples/pipeline/examples/meter.cli          |   58 +-
 examples/pipeline/examples/mirroring.cli      |   46 +-
 examples/pipeline/examples/pcap.io            |   27 +
 examples/pipeline/examples/recirculation.cli  |   41 +-
 examples/pipeline/examples/registers.cli      |   53 +-
 examples/pipeline/examples/selector.cli       |   55 +-
 examples/pipeline/examples/varbit.cli         |   41 +-
 examples/pipeline/examples/vxlan.cli          |   48 +-
 examples/pipeline/examples/vxlan_pcap.cli     |   39 +-
 examples/pipeline/obj.c                       |  172 +-
 examples/pipeline/obj.h                       |   46 -
 examples/pipeline/thread.c                    |   65 +-
 examples/pipeline/thread.h                    |    9 +-
 lib/pipeline/rte_swx_ctl.c                    |   99 +
 lib/pipeline/rte_swx_ctl.h                    |   15 +
 lib/pipeline/rte_swx_pipeline.c               |  464 ++--
 lib/pipeline/rte_swx_pipeline.h               |   71 +-
 lib/pipeline/rte_swx_pipeline_internal.h      |    2 +
 lib/pipeline/rte_swx_pipeline_spec.c          | 2050 +++++++++++++++--
 lib/pipeline/rte_swx_pipeline_spec.h          |  280 +++
 lib/pipeline/version.map                      |    7 +-
 30 files changed, 3430 insertions(+), 1704 deletions(-)
 create mode 100644 examples/pipeline/examples/ethdev.io
 create mode 100644 examples/pipeline/examples/pcap.io
 create mode 100644 lib/pipeline/rte_swx_pipeline_spec.h

-- 
2.34.1


^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH V6 01/17] pipeline: add pipeline name
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
                     ` (16 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add an unique name to every pipeline. This enables the library to
maintain a list of the existing pipeline objects, which can be
queried by the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/obj.c                  |   2 +-
 lib/pipeline/rte_swx_ctl.c               |  99 +++++++++++++++++++++
 lib/pipeline/rte_swx_ctl.h               |  15 ++++
 lib/pipeline/rte_swx_pipeline.c          | 107 ++++++++++++++++++++++-
 lib/pipeline/rte_swx_pipeline.h          |  18 +++-
 lib/pipeline/rte_swx_pipeline_internal.h |   2 +
 lib/pipeline/version.map                 |   4 +
 7 files changed, 244 insertions(+), 3 deletions(-)

diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index b79f044ac7..967342c580 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -533,7 +533,7 @@ pipeline_create(struct obj *obj, const char *name, int numa_node)
 		return NULL;
 
 	/* Resource create */
-	status = rte_swx_pipeline_config(&p, numa_node);
+	status = rte_swx_pipeline_config(&p, name, numa_node);
 	if (status)
 		goto error;
 
diff --git a/lib/pipeline/rte_swx_ctl.c b/lib/pipeline/rte_swx_ctl.c
index 710e89a46a..1b776fc543 100644
--- a/lib/pipeline/rte_swx_ctl.c
+++ b/lib/pipeline/rte_swx_ctl.c
@@ -9,6 +9,8 @@
 
 #include <rte_common.h>
 #include <rte_byteorder.h>
+#include <rte_tailq.h>
+#include <rte_eal_memconfig.h>
 
 #include <rte_swx_table_selector.h>
 
@@ -1157,12 +1159,103 @@ table_state_create(struct rte_swx_ctl_pipeline *ctl)
 	return status;
 }
 
+/* Global list of pipeline instances. */
+TAILQ_HEAD(rte_swx_ctl_pipeline_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_swx_ctl_pipeline_tailq = {
+	.name = "RTE_SWX_CTL_PIPELINE",
+};
+
+EAL_REGISTER_TAILQ(rte_swx_ctl_pipeline_tailq)
+
+struct rte_swx_ctl_pipeline *
+rte_swx_ctl_pipeline_find(const char *name)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	if (!name || !name[0] || (strnlen(name, RTE_SWX_CTL_NAME_SIZE) >= RTE_SWX_CTL_NAME_SIZE))
+		return NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_read_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		struct rte_swx_ctl_pipeline *ctl = (struct rte_swx_ctl_pipeline *)te->data;
+
+		if (!strncmp(name, ctl->info.name, sizeof(ctl->info.name))) {
+			rte_mcfg_tailq_read_unlock();
+			return ctl;
+		}
+	}
+
+	rte_mcfg_tailq_read_unlock();
+	return NULL;
+}
+
+static int
+ctl_register(struct rte_swx_ctl_pipeline *ctl)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		struct rte_swx_ctl_pipeline *ctl_crt = (struct rte_swx_ctl_pipeline *)te->data;
+
+		if (!strncmp(ctl->info.name, ctl_crt->info.name, sizeof(ctl->info.name))) {
+			rte_mcfg_tailq_write_unlock();
+			return -EEXIST;
+		}
+	}
+
+	te = calloc(1, sizeof(struct rte_tailq_entry));
+	if (!te) {
+		rte_mcfg_tailq_write_unlock();
+		return -ENOMEM;
+	}
+
+	te->data = (void *)ctl;
+	TAILQ_INSERT_TAIL(ctl_list, te, next);
+	rte_mcfg_tailq_write_unlock();
+	return 0;
+}
+
+static void
+ctl_unregister(struct rte_swx_ctl_pipeline *ctl)
+{
+	struct rte_swx_ctl_pipeline_list *ctl_list;
+	struct rte_tailq_entry *te = NULL;
+
+	ctl_list = RTE_TAILQ_CAST(rte_swx_ctl_pipeline_tailq.head, rte_swx_ctl_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, ctl_list, next) {
+		if (te->data == (void *)ctl) {
+			TAILQ_REMOVE(ctl_list, te, next);
+			rte_mcfg_tailq_write_unlock();
+			free(te);
+			return;
+		}
+	}
+
+	rte_mcfg_tailq_write_unlock();
+}
+
 void
 rte_swx_ctl_pipeline_free(struct rte_swx_ctl_pipeline *ctl)
 {
 	if (!ctl)
 		return;
 
+	if (ctl->info.name[0])
+		ctl_unregister(ctl);
+
 	action_free(ctl);
 
 	table_state_free(ctl);
@@ -1441,6 +1534,12 @@ rte_swx_ctl_pipeline_create(struct rte_swx_pipeline *p)
 	if (status)
 		goto error;
 
+	if (ctl->info.name[0]) {
+		status = ctl_register(ctl);
+		if (status)
+			goto error;
+	}
+
 	return ctl;
 
 error:
diff --git a/lib/pipeline/rte_swx_ctl.h b/lib/pipeline/rte_swx_ctl.h
index d771389d26..63ee479e47 100644
--- a/lib/pipeline/rte_swx_ctl.h
+++ b/lib/pipeline/rte_swx_ctl.h
@@ -35,6 +35,9 @@ struct rte_swx_pipeline;
 
 /** Pipeline info. */
 struct rte_swx_ctl_pipeline_info {
+	/** Pipeline name. */
+	char name[RTE_SWX_CTL_NAME_SIZE];
+
 	/** Number of input ports. */
 	uint32_t n_ports_in;
 
@@ -812,6 +815,18 @@ rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p,
 /** Pipeline control opaque data structure. */
 struct rte_swx_ctl_pipeline;
 
+/**
+ * Pipeline control find
+ *
+ * @param[in] name
+ *   Pipeline name.
+ * @return
+ *   Valid pipeline control handle if found or NULL otherwise.
+ */
+__rte_experimental
+struct rte_swx_ctl_pipeline *
+rte_swx_ctl_pipeline_find(const char *name);
+
 /**
  * Pipeline control create
  *
diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index 3e1c6e9edb..c8ccded4f8 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -6,6 +6,8 @@
 #include <errno.h>
 #include <dlfcn.h>
 
+#include <rte_tailq.h>
+#include <rte_eal_memconfig.h>
 #include <rte_jhash.h>
 #include <rte_hash_crc.h>
 
@@ -9578,6 +9580,95 @@ metarray_free(struct rte_swx_pipeline *p)
 /*
  * Pipeline.
  */
+
+/* Global list of pipeline instances. */
+TAILQ_HEAD(rte_swx_pipeline_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_swx_pipeline_tailq = {
+	.name = "RTE_SWX_PIPELINE",
+};
+
+EAL_REGISTER_TAILQ(rte_swx_pipeline_tailq)
+
+struct rte_swx_pipeline *
+rte_swx_pipeline_find(const char *name)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	if (!name || !name[0] || (strnlen(name, RTE_SWX_NAME_SIZE) >= RTE_SWX_NAME_SIZE))
+		return NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_read_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		struct rte_swx_pipeline *p = (struct rte_swx_pipeline *)te->data;
+
+		if (!strncmp(name, p->name, sizeof(p->name))) {
+			rte_mcfg_tailq_read_unlock();
+			return p;
+		}
+	}
+
+	rte_mcfg_tailq_read_unlock();
+	return NULL;
+}
+
+static int
+pipeline_register(struct rte_swx_pipeline *p)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		struct rte_swx_pipeline *pipeline = (struct rte_swx_pipeline *)te->data;
+
+		if (!strncmp(p->name, pipeline->name, sizeof(p->name))) {
+			rte_mcfg_tailq_write_unlock();
+			return -EEXIST;
+		}
+	}
+
+	te = calloc(1, sizeof(struct rte_tailq_entry));
+	if (!te) {
+		rte_mcfg_tailq_write_unlock();
+		return -ENOMEM;
+	}
+
+	te->data = (void *)p;
+	TAILQ_INSERT_TAIL(pipeline_list, te, next);
+	rte_mcfg_tailq_write_unlock();
+	return 0;
+}
+
+static void
+pipeline_unregister(struct rte_swx_pipeline *p)
+{
+	struct rte_swx_pipeline_list *pipeline_list;
+	struct rte_tailq_entry *te = NULL;
+
+	pipeline_list = RTE_TAILQ_CAST(rte_swx_pipeline_tailq.head, rte_swx_pipeline_list);
+
+	rte_mcfg_tailq_write_lock();
+
+	TAILQ_FOREACH(te, pipeline_list, next) {
+		if (te->data == (void *)p) {
+			TAILQ_REMOVE(pipeline_list, te, next);
+			rte_mcfg_tailq_write_unlock();
+			free(te);
+			return;
+		}
+	}
+
+	rte_mcfg_tailq_write_unlock();
+}
+
 void
 rte_swx_pipeline_free(struct rte_swx_pipeline *p)
 {
@@ -9586,6 +9677,9 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p)
 	if (!p)
 		return;
 
+	if (p->name[0])
+		pipeline_unregister(p);
+
 	lib = p->lib;
 
 	free(p->instruction_data);
@@ -9720,13 +9814,14 @@ hash_funcs_register(struct rte_swx_pipeline *p)
 }
 
 int
-rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
+rte_swx_pipeline_config(struct rte_swx_pipeline **p, const char *name, int numa_node)
 {
 	struct rte_swx_pipeline *pipeline = NULL;
 	int status = 0;
 
 	/* Check input parameters. */
 	CHECK(p, EINVAL);
+	CHECK(!name || (strnlen(name, RTE_SWX_NAME_SIZE) < RTE_SWX_NAME_SIZE), EINVAL);
 
 	/* Memory allocation. */
 	pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
@@ -9736,6 +9831,9 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
 	}
 
 	/* Initialization. */
+	if (name)
+		strcpy(pipeline->name, name);
+
 	TAILQ_INIT(&pipeline->struct_types);
 	TAILQ_INIT(&pipeline->port_in_types);
 	TAILQ_INIT(&pipeline->ports_in);
@@ -9776,6 +9874,12 @@ rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
 	if (status)
 		goto error;
 
+	if (pipeline->name[0]) {
+		status = pipeline_register(pipeline);
+		if (status)
+			goto error;
+	}
+
 	*p = pipeline;
 	return 0;
 
@@ -9966,6 +10070,7 @@ rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p,
 	TAILQ_FOREACH(table, &p->tables, node)
 		n_tables++;
 
+	strcpy(pipeline->name, p->name);
 	pipeline->n_ports_in = p->n_ports_in;
 	pipeline->n_ports_out = p->n_ports_out;
 	pipeline->n_mirroring_slots = p->n_mirroring_slots;
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index c41ca5cb15..ef50a0fa70 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -44,22 +44,38 @@ extern "C" {
 /** Pipeline opaque data structure. */
 struct rte_swx_pipeline;
 
+/**
+ * Pipeline find
+ *
+ * @param[in] name
+ *   Pipeline name.
+ * @return
+ *   Valid pipeline handle if found or NULL otherwise.
+ */
+__rte_experimental
+struct rte_swx_pipeline *
+rte_swx_pipeline_find(const char *name);
+
 /**
  * Pipeline configure
  *
  * @param[out] p
  *   Pipeline handle. Must point to valid memory. Contains valid pipeline handle
  *   when the function returns successfully.
+ * @param[in] name
+ *   Pipeline unique name.
  * @param[in] numa_node
  *   Non-Uniform Memory Access (NUMA) node.
  * @return
  *   0 on success or the following error codes otherwise:
  *   -EINVAL: Invalid argument;
- *   -ENOMEM: Not enough space/cannot allocate memory.
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -EEXIST: Pipeline with this name already exists.
  */
 __rte_experimental
 int
 rte_swx_pipeline_config(struct rte_swx_pipeline **p,
+			const char *name,
 			int numa_node);
 
 /*
diff --git a/lib/pipeline/rte_swx_pipeline_internal.h b/lib/pipeline/rte_swx_pipeline_internal.h
index a35635efb7..588cad62b5 100644
--- a/lib/pipeline/rte_swx_pipeline_internal.h
+++ b/lib/pipeline/rte_swx_pipeline_internal.h
@@ -1459,6 +1459,8 @@ instr_operand_nbo(struct thread *t, const struct instr_operand *x)
 #endif
 
 struct rte_swx_pipeline {
+	char name[RTE_SWX_NAME_SIZE];
+
 	struct struct_type_tailq struct_types;
 	struct port_in_type_tailq port_in_types;
 	struct port_in_tailq ports_in;
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 8312307a7a..50029aadcf 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -145,4 +145,8 @@ EXPERIMENTAL {
 	rte_swx_ctl_pipeline_learner_timeout_get;
 	rte_swx_ctl_pipeline_learner_timeout_set;
 	rte_swx_pipeline_hash_func_register;
+
+	#added in 22.11
+	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 02/17] pipeline: move specification data structures to internal header
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 01/17] pipeline: add pipeline name Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
                     ` (15 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Move all the pipeline object specification data structures to an
internal header file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 126 +------------------
 lib/pipeline/rte_swx_pipeline_spec.h | 176 +++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 125 deletions(-)
 create mode 100644 lib/pipeline/rte_swx_pipeline_spec.h

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 904b9eb471..5e07b4f794 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -9,7 +9,7 @@
 
 #include <rte_common.h>
 
-#include "rte_swx_pipeline.h"
+#include "rte_swx_pipeline_spec.h"
 
 #ifndef MAX_LINE_LENGTH
 #define MAX_LINE_LENGTH 2048
@@ -34,15 +34,7 @@
 
 /*
  * extobj.
- *
- * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
  */
-struct extobj_spec {
-	char *name;
-	char *extern_type_name;
-	char *pragma;
-};
-
 static void
 extobj_spec_free(struct extobj_spec *s)
 {
@@ -104,18 +96,7 @@ extobj_statement_parse(struct extobj_spec *s,
 /*
  * struct.
  *
- * struct STRUCT_TYPE_NAME {
- *	bit<SIZE> | varbit<SIZE> FIELD_NAME
- *	...
- * }
  */
-struct struct_spec {
-	char *name;
-	struct rte_swx_field_params *fields;
-	uint32_t n_fields;
-	int varbit;
-};
-
 static void
 struct_spec_free(struct struct_spec *s)
 {
@@ -293,13 +274,7 @@ struct_block_parse(struct struct_spec *s,
 /*
  * header.
  *
- * header HEADER_NAME instanceof STRUCT_TYPE_NAME
  */
-struct header_spec {
-	char *name;
-	char *struct_type_name;
-};
-
 static void
 header_spec_free(struct header_spec *s)
 {
@@ -351,12 +326,7 @@ header_statement_parse(struct header_spec *s,
 /*
  * metadata.
  *
- * metadata instanceof STRUCT_TYPE_NAME
  */
-struct metadata_spec {
-	char *struct_type_name;
-};
-
 static void
 metadata_spec_free(struct metadata_spec *s)
 {
@@ -400,18 +370,7 @@ metadata_statement_parse(struct metadata_spec *s,
 /*
  * action.
  *
- * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
- *	INSTRUCTION
- *	...
- * }
  */
-struct action_spec {
-	char *name;
-	char *args_struct_type_name;
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 action_spec_free(struct action_spec *s)
 {
@@ -540,29 +499,7 @@ action_block_parse(struct action_spec *s,
 /*
  * table.
  *
- * table TABLE_NAME {
- *	key {
- *		MATCH_FIELD_NAME exact | wildcard | lpm
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly ]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	instanceof TABLE_TYPE_NAME
- *	pragma ARGS
- *	size SIZE
- * }
  */
-struct table_spec {
-	char *name;
-	struct rte_swx_pipeline_table_params params;
-	char *recommended_table_type_name;
-	char *args;
-	uint32_t size;
-};
-
 static void
 table_spec_free(struct table_spec *s)
 {
@@ -1084,22 +1021,7 @@ table_block_parse(struct table_spec *s,
 /*
  * selector.
  *
- * selector SELECTOR_NAME {
- *	group_id FIELD_NAME
- *	selector {
- *		FIELD_NAME
- *		...
- *	}
- *	member_id FIELD_NAME
- *	n_groups N_GROUPS
- *	n_members_per_group N_MEMBERS_PER_GROUP
- * }
  */
-struct selector_spec {
-	char *name;
-	struct rte_swx_pipeline_selector_params params;
-};
-
 static void
 selector_spec_free(struct selector_spec *s)
 {
@@ -1385,31 +1307,7 @@ selector_block_parse(struct selector_spec *s,
 /*
  * learner.
  *
- * learner LEARNER_NAME {
- *	key {
- *		MATCH_FIELD_NAME
- *		...
- *	}
- *	actions {
- *		ACTION_NAME [ @tableonly | @defaultonly]
- *		...
- *	}
- *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
- *	size SIZE
- *	timeout {
- *		TIMEOUT_IN_SECONDS
- *		...
- *	}
- * }
  */
-struct learner_spec {
-	char *name;
-	struct rte_swx_pipeline_learner_params params;
-	uint32_t size;
-	uint32_t *timeout;
-	uint32_t n_timeouts;
-};
-
 static void
 learner_spec_free(struct learner_spec *s)
 {
@@ -1958,14 +1856,7 @@ learner_block_parse(struct learner_spec *s,
 /*
  * regarray.
  *
- * regarray NAME size SIZE initval INITVAL
  */
-struct regarray_spec {
-	char *name;
-	uint64_t init_val;
-	uint32_t size;
-};
-
 static void
 regarray_spec_free(struct regarray_spec *s)
 {
@@ -2033,13 +1924,7 @@ regarray_statement_parse(struct regarray_spec *s,
 /*
  * metarray.
  *
- * metarray NAME size SIZE
  */
-struct metarray_spec {
-	char *name;
-	uint32_t size;
-};
-
 static void
 metarray_spec_free(struct metarray_spec *s)
 {
@@ -2095,16 +1980,7 @@ metarray_statement_parse(struct metarray_spec *s,
 /*
  * apply.
  *
- * apply {
- *	INSTRUCTION
- *	...
- * }
  */
-struct apply_spec {
-	const char **instructions;
-	uint32_t n_instructions;
-};
-
 static void
 apply_spec_free(struct apply_spec *s)
 {
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
new file mode 100644
index 0000000000..8458de878a
--- /dev/null
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Intel Corporation
+ */
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_common.h>
+
+#include <rte_swx_pipeline.h>
+
+/*
+ * extobj.
+ *
+ * extobj OBJ_NAME instanceof OBJ_TYPE [ pragma OBJ_CREATE_ARGS ]
+ */
+struct extobj_spec {
+	char *name;
+	char *extern_type_name;
+	char *pragma;
+};
+
+/*
+ * struct.
+ *
+ * struct STRUCT_TYPE_NAME {
+ *	bit<SIZE> | varbit<SIZE> FIELD_NAME
+ *	...
+ * }
+ */
+struct struct_spec {
+	char *name;
+	struct rte_swx_field_params *fields;
+	uint32_t n_fields;
+	int varbit;
+};
+
+/*
+ * header.
+ *
+ * header HEADER_NAME instanceof STRUCT_TYPE_NAME
+ */
+struct header_spec {
+	char *name;
+	char *struct_type_name;
+};
+
+/*
+ * metadata.
+ *
+ * metadata instanceof STRUCT_TYPE_NAME
+ */
+struct metadata_spec {
+	char *struct_type_name;
+};
+
+/*
+ * action.
+ *
+ * action ACTION_NAME args none | instanceof STRUCT_TYPE_NAME {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct action_spec {
+	char *name;
+	char *args_struct_type_name;
+	const char **instructions;
+	uint32_t n_instructions;
+};
+
+/*
+ * table.
+ *
+ * table TABLE_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME exact | wildcard | lpm
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly ]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	instanceof TABLE_TYPE_NAME
+ *	pragma ARGS
+ *	size SIZE
+ * }
+ */
+struct table_spec {
+	char *name;
+	struct rte_swx_pipeline_table_params params;
+	char *recommended_table_type_name;
+	char *args;
+	uint32_t size;
+};
+
+/*
+ * selector.
+ *
+ * selector SELECTOR_NAME {
+ *	group_id FIELD_NAME
+ *	selector {
+ *		FIELD_NAME
+ *		...
+ *	}
+ *	member_id FIELD_NAME
+ *	n_groups N_GROUPS
+ *	n_members_per_group N_MEMBERS_PER_GROUP
+ * }
+ */
+struct selector_spec {
+	char *name;
+	struct rte_swx_pipeline_selector_params params;
+};
+
+/*
+ * learner.
+ *
+ * learner LEARNER_NAME {
+ *	key {
+ *		MATCH_FIELD_NAME
+ *		...
+ *	}
+ *	actions {
+ *		ACTION_NAME [ @tableonly | @defaultonly]
+ *		...
+ *	}
+ *	default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ]
+ *	size SIZE
+ *	timeout {
+ *		TIMEOUT_IN_SECONDS
+ *		...
+ *	}
+ * }
+ */
+struct learner_spec {
+	char *name;
+	struct rte_swx_pipeline_learner_params params;
+	uint32_t size;
+	uint32_t *timeout;
+	uint32_t n_timeouts;
+};
+
+/*
+ * regarray.
+ *
+ * regarray NAME size SIZE initval INITVAL
+ */
+struct regarray_spec {
+	char *name;
+	uint64_t init_val;
+	uint32_t size;
+};
+
+/*
+ * metarray.
+ *
+ * metarray NAME size SIZE
+ */
+struct metarray_spec {
+	char *name;
+	uint32_t size;
+};
+
+/*
+ * apply.
+ *
+ * apply {
+ *	INSTRUCTION
+ *	...
+ * }
+ */
+struct apply_spec {
+	const char **instructions;
+	uint32_t n_instructions;
+};
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 03/17] pipeline: add pipeline specification data structure
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 01/17] pipeline: add pipeline name Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
                     ` (14 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add specification data structure for the entire pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 21 ++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h | 32 ++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 5e07b4f794..642091b678 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2082,6 +2082,27 @@ apply_block_parse(struct apply_spec *s,
 /*
  * Pipeline.
  */
+void
+pipeline_spec_free(struct pipeline_spec *s)
+{
+	if (!s)
+		return;
+
+	free(s->extobjs);
+	free(s->structs);
+	free(s->headers);
+	free(s->metadata);
+	free(s->actions);
+	free(s->tables);
+	free(s->selectors);
+	free(s->learners);
+	free(s->regarrays);
+	free(s->metarrays);
+	free(s->apply);
+
+	memset(s, 0, sizeof(struct pipeline_spec));
+}
+
 int
 rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				 FILE *spec,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 8458de878a..e1170a33b1 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -174,3 +174,35 @@ struct apply_spec {
 	const char **instructions;
 	uint32_t n_instructions;
 };
+
+/*
+ * Pipeline.
+ */
+struct pipeline_spec {
+	struct extobj_spec *extobjs;
+	struct struct_spec *structs;
+	struct header_spec *headers;
+	struct metadata_spec *metadata;
+	struct action_spec *actions;
+	struct table_spec *tables;
+	struct selector_spec *selectors;
+	struct learner_spec *learners;
+	struct regarray_spec *regarrays;
+	struct metarray_spec *metarrays;
+	struct apply_spec *apply;
+
+	uint32_t n_extobjs;
+	uint32_t n_structs;
+	uint32_t n_headers;
+	uint32_t n_metadata;
+	uint32_t n_actions;
+	uint32_t n_tables;
+	uint32_t n_selectors;
+	uint32_t n_learners;
+	uint32_t n_regarrays;
+	uint32_t n_metarrays;
+	uint32_t n_apply;
+};
+
+void
+pipeline_spec_free(struct pipeline_spec *s);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 04/17] pipeline: rework the specification file-based pipeline build
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (2 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
                     ` (13 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Rework the specification file-based pipeline build operation to first
parse the specification file into the previously introduced pipeline
specification data structure, then use this structure to configure
and build the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 478 +++++++++++++++++++++------
 lib/pipeline/rte_swx_pipeline_spec.h |   9 +
 2 files changed, 385 insertions(+), 102 deletions(-)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 642091b678..62929a9da6 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2103,11 +2103,10 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg)
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg)
 {
 	struct extobj_spec extobj_spec = {0};
 	struct struct_spec struct_spec = {0};
@@ -2120,26 +2119,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	struct regarray_spec regarray_spec = {0};
 	struct metarray_spec metarray_spec = {0};
 	struct apply_spec apply_spec = {0};
-	uint32_t n_lines;
+	struct pipeline_spec *s = NULL;
+	uint32_t n_lines = 0;
 	uint32_t block_mask = 0;
-	int status;
+	int status = 0;
 
 	/* Check the input arguments. */
-	if (!p) {
+	if (!spec) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null pipeline argument.";
+			*err_msg = "Invalid input argument.";
 		status = -EINVAL;
 		goto error;
 	}
 
-	if (!spec) {
+	/* Memory allocation. */
+	s = calloc(sizeof(struct pipeline_spec), 1);
+	if (!s) {
 		if (err_line)
-			*err_line = 0;
+			*err_line = n_lines;
 		if (err_msg)
-			*err_msg = "Null specification file argument.";
-		status = -EINVAL;
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
 		goto error;
 	}
 
@@ -2200,6 +2202,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* struct block. */
 		if (block_mask & (1 << STRUCT_BLOCK)) {
+			struct struct_spec *new_structs;
+
 			status = struct_block_parse(&struct_spec,
 						    &block_mask,
 						    tokens,
@@ -2214,26 +2218,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_struct_type_register(p,
-				struct_spec.name,
-				struct_spec.fields,
-				struct_spec.n_fields,
-				struct_spec.varbit);
-			if (status) {
+			new_structs = realloc(s->structs,
+					      (s->n_structs + 1) * sizeof(struct struct_spec));
+			if (!new_structs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Struct registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			struct_spec_free(&struct_spec);
+			s->structs = new_structs;
+			memcpy(&s->structs[s->n_structs], &struct_spec, sizeof(struct struct_spec));
+			s->n_structs++;
+			memset(&struct_spec, 0, sizeof(struct struct_spec));
 
 			continue;
 		}
 
 		/* action block. */
 		if (block_mask & (1 << ACTION_BLOCK)) {
+			struct action_spec *new_actions;
+
 			status = action_block_parse(&action_spec,
 						    &block_mask,
 						    tokens,
@@ -2248,26 +2255,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_action_config(p,
-				action_spec.name,
-				action_spec.args_struct_type_name,
-				action_spec.instructions,
-				action_spec.n_instructions);
-			if (status) {
+			new_actions = realloc(s->actions,
+					      (s->n_actions + 1) * sizeof(struct action_spec));
+			if (!new_actions) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Action config error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			action_spec_free(&action_spec);
+			s->actions = new_actions;
+			memcpy(&s->actions[s->n_actions], &action_spec, sizeof(struct action_spec));
+			s->n_actions++;
+			memset(&action_spec, 0, sizeof(struct action_spec));
 
 			continue;
 		}
 
 		/* table block. */
 		if (block_mask & (1 << TABLE_BLOCK)) {
+			struct table_spec *new_tables;
+
 			status = table_block_parse(&table_spec,
 						   &block_mask,
 						   tokens,
@@ -2282,27 +2292,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_table_config(p,
-				table_spec.name,
-				&table_spec.params,
-				table_spec.recommended_table_type_name,
-				table_spec.args,
-				table_spec.size);
-			if (status) {
+			new_tables = realloc(s->tables,
+					     (s->n_tables + 1) * sizeof(struct table_spec));
+			if (!new_tables) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			table_spec_free(&table_spec);
+			s->tables = new_tables;
+			memcpy(&s->tables[s->n_tables], &table_spec, sizeof(struct table_spec));
+			s->n_tables++;
+			memset(&table_spec, 0, sizeof(struct table_spec));
 
 			continue;
 		}
 
 		/* selector block. */
 		if (block_mask & (1 << SELECTOR_BLOCK)) {
+			struct selector_spec *new_selectors;
+
 			status = selector_block_parse(&selector_spec,
 						      &block_mask,
 						      tokens,
@@ -2317,24 +2329,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_selector_config(p,
-				selector_spec.name,
-				&selector_spec.params);
-			if (status) {
+			new_selectors = realloc(s->selectors,
+				(s->n_selectors + 1) * sizeof(struct selector_spec));
+			if (!new_selectors) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Selector configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			selector_spec_free(&selector_spec);
+			s->selectors = new_selectors;
+			memcpy(&s->selectors[s->n_selectors],
+			       &selector_spec,
+			       sizeof(struct selector_spec));
+			s->n_selectors++;
+			memset(&selector_spec, 0, sizeof(struct selector_spec));
 
 			continue;
 		}
 
 		/* learner block. */
 		if (block_mask & (1 << LEARNER_BLOCK)) {
+			struct learner_spec *new_learners;
+
 			status = learner_block_parse(&learner_spec,
 						     &block_mask,
 						     tokens,
@@ -2349,27 +2368,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_learner_config(p,
-				learner_spec.name,
-				&learner_spec.params,
-				learner_spec.size,
-				learner_spec.timeout,
-				learner_spec.n_timeouts);
-			if (status) {
+			new_learners = realloc(s->learners,
+					       (s->n_learners + 1) * sizeof(struct learner_spec));
+			if (!new_learners) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Learner table configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			learner_spec_free(&learner_spec);
+			s->learners = new_learners;
+			memcpy(&s->learners[s->n_learners],
+			       &learner_spec,
+			       sizeof(struct learner_spec));
+			s->n_learners++;
+			memset(&learner_spec, 0, sizeof(struct learner_spec));
 
 			continue;
 		}
 
 		/* apply block. */
 		if (block_mask & (1 << APPLY_BLOCK)) {
+			struct apply_spec *new_apply;
+
 			status = apply_block_parse(&apply_spec,
 						   &block_mask,
 						   tokens,
@@ -2384,24 +2407,28 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 				continue;
 
 			/* End of block. */
-			status = rte_swx_pipeline_instructions_config(p,
-				apply_spec.instructions,
-				apply_spec.n_instructions);
-			if (status) {
+			new_apply = realloc(s->apply, (s->n_apply + 1) * sizeof(struct apply_spec));
+			if (!new_apply) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Pipeline instructions err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			apply_spec_free(&apply_spec);
+			s->apply = new_apply;
+			memcpy(&s->apply[s->n_apply], &apply_spec, sizeof(struct apply_spec));
+			s->n_apply++;
+			memset(&apply_spec, 0, sizeof(struct apply_spec));
 
 			continue;
 		}
 
 		/* extobj. */
 		if (!strcmp(tokens[0], "extobj")) {
+			struct extobj_spec *new_extobjs;
+
 			status = extobj_statement_parse(&extobj_spec,
 							tokens,
 							n_tokens,
@@ -2411,19 +2438,21 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_extern_object_config(p,
-				extobj_spec.name,
-				extobj_spec.extern_type_name,
-				extobj_spec.pragma);
-			if (status) {
+			new_extobjs = realloc(s->extobjs,
+					      (s->n_extobjs + 1) * sizeof(struct extobj_spec));
+			if (!new_extobjs) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Extern object config err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			extobj_spec_free(&extobj_spec);
+			s->extobjs = new_extobjs;
+			memcpy(&s->extobjs[s->n_extobjs], &extobj_spec, sizeof(struct extobj_spec));
+			s->n_extobjs++;
+			memset(&extobj_spec, 0, sizeof(struct extobj_spec));
 
 			continue;
 		}
@@ -2445,6 +2474,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* header. */
 		if (!strcmp(tokens[0], "header")) {
+			struct header_spec *new_headers;
+
 			status = header_statement_parse(&header_spec,
 							tokens,
 							n_tokens,
@@ -2454,24 +2485,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_header_register(p,
-				header_spec.name,
-				header_spec.struct_type_name);
-			if (status) {
+			new_headers = realloc(s->headers,
+					      (s->n_headers + 1) * sizeof(struct header_spec));
+			if (!new_headers) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Header registration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			header_spec_free(&header_spec);
+			s->headers = new_headers;
+			memcpy(&s->headers[s->n_headers], &header_spec, sizeof(struct header_spec));
+			s->n_headers++;
+			memset(&header_spec, 0, sizeof(struct header_spec));
 
 			continue;
 		}
 
 		/* metadata. */
 		if (!strcmp(tokens[0], "metadata")) {
+			struct metadata_spec *new_metadata;
+
 			status = metadata_statement_parse(&metadata_spec,
 							  tokens,
 							  n_tokens,
@@ -2481,17 +2517,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_packet_metadata_register(p,
-				metadata_spec.struct_type_name);
-			if (status) {
+			new_metadata = realloc(s->metadata,
+					       (s->n_metadata + 1) * sizeof(struct metadata_spec));
+			if (!new_metadata) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meta-data reg err.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metadata_spec_free(&metadata_spec);
+			s->metadata = new_metadata;
+			memcpy(&s->metadata[s->n_metadata],
+			       &metadata_spec,
+			       sizeof(struct metadata_spec));
+			s->n_metadata++;
+			memset(&metadata_spec, 0, sizeof(struct metadata_spec));
 
 			continue;
 		}
@@ -2558,6 +2600,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 
 		/* regarray. */
 		if (!strcmp(tokens[0], "regarray")) {
+			struct regarray_spec *new_regarrays;
+
 			status = regarray_statement_parse(&regarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2567,25 +2611,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_regarray_config(p,
-				regarray_spec.name,
-				regarray_spec.size,
-				regarray_spec.init_val);
-			if (status) {
+			new_regarrays = realloc(s->regarrays,
+				(s->n_regarrays + 1) * sizeof(struct regarray_spec));
+			if (!new_regarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Register array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			regarray_spec_free(&regarray_spec);
+			s->regarrays = new_regarrays;
+			memcpy(&s->regarrays[s->n_regarrays],
+			       &regarray_spec,
+			       sizeof(struct regarray_spec));
+			s->n_regarrays++;
+			memset(&regarray_spec, 0, sizeof(struct regarray_spec));
 
 			continue;
 		}
 
 		/* metarray. */
 		if (!strcmp(tokens[0], "metarray")) {
+			struct metarray_spec *new_metarrays;
+
 			status = metarray_statement_parse(&metarray_spec,
 							  tokens,
 							  n_tokens,
@@ -2595,18 +2645,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 			if (status)
 				goto error;
 
-			status = rte_swx_pipeline_metarray_config(p,
-				metarray_spec.name,
-				metarray_spec.size);
-			if (status) {
+			new_metarrays = realloc(s->metarrays,
+				(s->n_metarrays + 1) * sizeof(struct metarray_spec));
+			if (!new_metarrays) {
 				if (err_line)
 					*err_line = n_lines;
 				if (err_msg)
-					*err_msg = "Meter array configuration error.";
+					*err_msg = "Memory allocation failed.";
+				status = -ENOMEM;
 				goto error;
 			}
 
-			metarray_spec_free(&metarray_spec);
+			s->metarrays = new_metarrays;
+			memcpy(&s->metarrays[s->n_metarrays],
+			       &metarray_spec,
+			       sizeof(struct metarray_spec));
+			s->n_metarrays++;
+			memset(&metarray_spec, 0, sizeof(struct metarray_spec));
 
 			continue;
 		}
@@ -2644,17 +2699,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 		goto error;
 	}
 
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = n_lines;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
+	return s;
 
 error:
 	extobj_spec_free(&extobj_spec);
@@ -2668,5 +2713,234 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	regarray_spec_free(&regarray_spec);
 	metarray_spec_free(&metarray_spec);
 	apply_spec_free(&apply_spec);
+	pipeline_spec_free(s);
+
+	return NULL;
+}
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg)
+{
+	uint32_t i;
+	int status = 0;
+
+	/* extobj. */
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		status = rte_swx_pipeline_extern_object_config(p,
+			extobj_spec->name,
+			extobj_spec->extern_type_name,
+			extobj_spec->pragma);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Extern object configuration error.";
+			return status;
+		}
+	}
+
+	/* regarray. */
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		status = rte_swx_pipeline_regarray_config(p,
+			regarray_spec->name,
+			regarray_spec->size,
+			regarray_spec->init_val);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Register array configuration error.";
+			return status;
+		}
+	}
+
+	/* metarray. */
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		status = rte_swx_pipeline_metarray_config(p,
+			metarray_spec->name,
+			metarray_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meter array configuration error.";
+			return status;
+		}
+	}
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		status = rte_swx_pipeline_struct_type_register(p,
+			struct_spec->name,
+			struct_spec->fields,
+			struct_spec->n_fields,
+			struct_spec->varbit);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Struct type registration error.";
+			return status;
+		}
+	}
+
+	/* header. */
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		status = rte_swx_pipeline_packet_header_register(p,
+			header_spec->name,
+			header_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Header configuration error.";
+			return status;
+		}
+	}
+
+	/* metadata. */
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		status = rte_swx_pipeline_packet_metadata_register(p,
+			metadata_spec->struct_type_name);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Meta-data registration error.";
+			return status;
+		}
+	}
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		status = rte_swx_pipeline_action_config(p,
+			action_spec->name,
+			action_spec->args_struct_type_name,
+			action_spec->instructions,
+			action_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Action configuration error.";
+			return status;
+		}
+	}
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		status = rte_swx_pipeline_table_config(p,
+			table_spec->name,
+			&table_spec->params,
+			table_spec->recommended_table_type_name,
+			table_spec->args,
+			table_spec->size);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Table configuration error.";
+			return status;
+		}
+	}
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		status = rte_swx_pipeline_selector_config(p,
+			selector_spec->name,
+			&selector_spec->params);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Selector table configuration error.";
+			return status;
+		}
+	}
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		status = rte_swx_pipeline_learner_config(p,
+			learner_spec->name,
+			&learner_spec->params,
+			learner_spec->size,
+			learner_spec->timeout,
+			learner_spec->n_timeouts);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Learner table configuration error.";
+			return status;
+		}
+	}
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+
+		status = rte_swx_pipeline_instructions_config(p,
+			apply_spec->instructions,
+			apply_spec->n_instructions);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline instructions configuration error.";
+			return status;
+		}
+	}
+
+	return 0;
+}
+
+int
+rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
+				 FILE *spec_file,
+				 uint32_t *err_line,
+				 const char **err_msg)
+{
+	struct pipeline_spec *s = NULL;
+	int status = 0;
+
+	/* Check the input arguments. */
+	if (!p || !spec_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Spec file parse. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto error;
+	}
+
+	/* Pipeline configure. */
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto error;
+	}
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline build error.";
+		goto error;
+	}
+
+	return 0;
+
+error:
+	pipeline_spec_free(s);
 	return status;
 }
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index e1170a33b1..4f3a0b5958 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,3 +206,12 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+struct pipeline_spec *
+pipeline_spec_parse(FILE *spec,
+		    uint32_t *err_line,
+		    const char **err_msg);
+
+int
+pipeline_spec_configure(struct rte_swx_pipeline *p,
+			struct pipeline_spec *s,
+			const char **err_msg);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 05/17] pipeline: generate the code for pipeline specification structure
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (3 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
                     ` (12 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add support to export the pipeline specification data structure to a C
source code file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 622 +++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h |   5 +
 2 files changed, 627 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 62929a9da6..bf21fe17ba 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2020 Intel Corporation
  */
 #include <stdint.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -2103,6 +2104,627 @@ pipeline_spec_free(struct pipeline_spec *s)
 	memset(s, 0, sizeof(struct pipeline_spec));
 }
 
+static const char *
+match_type_string_get(enum rte_swx_table_match_type match_type)
+{
+	switch (match_type) {
+	case RTE_SWX_TABLE_MATCH_WILDCARD: return "RTE_SWX_TABLE_MATCH_WILDCARD";
+	case RTE_SWX_TABLE_MATCH_LPM: return "RTE_SWX_TABLE_MATCH_LPM";
+	case RTE_SWX_TABLE_MATCH_EXACT: return "RTE_SWX_TABLE_MATCH_EXACT";
+	default: return "RTE_SWX_TABLE_MATCH_UNKNOWN";
+	}
+}
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s)
+{
+	uint32_t i;
+
+	/* Check the input arguments. */
+	if (!f || !s)
+		return;
+
+	/* extobj. */
+	fprintf(f, "static struct extobj_spec extobjs[] = {\n");
+
+	for (i = 0; i < s->n_extobjs; i++) {
+		struct extobj_spec *extobj_spec = &s->extobjs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", extobj_spec->name);
+		fprintf(f, "\t\t.extern_type_name = \"%s\",\n", extobj_spec->extern_type_name);
+		if (extobj_spec->pragma)
+			fprintf(f, "\t\t.pragma = \"%s\",\n", extobj_spec->pragma);
+		else
+			fprintf(f, "\t\t.pragma = NULL,\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* regarray. */
+	fprintf(f, "static struct regarray_spec regarrays[] = {\n");
+
+	for (i = 0; i < s->n_regarrays; i++) {
+		struct regarray_spec *regarray_spec = &s->regarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", regarray_spec->name);
+		fprintf(f, "\t\t.init_val = %" PRIu64 ",\n", regarray_spec->init_val);
+		fprintf(f, "\t\t.size = %u,\n", regarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metarray. */
+	fprintf(f, "static struct metarray_spec metarrays[] = {\n");
+
+	for (i = 0; i < s->n_metarrays; i++) {
+		struct metarray_spec *metarray_spec = &s->metarrays[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", metarray_spec->name);
+		fprintf(f, "\t\t.size = %u,\n", metarray_spec->size);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* struct. */
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+		uint32_t j;
+
+		fprintf(f, "static struct rte_swx_field_params struct_%s_fields[] = {\n",
+			struct_spec->name);
+
+		for (j = 0; j < struct_spec->n_fields; j++) {
+			struct rte_swx_field_params *field = &struct_spec->fields[j];
+
+			fprintf(f, "\t[%d] = {\n", j);
+			fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+			fprintf(f, "\t\t.n_bits = %u,\n", field->n_bits);
+			fprintf(f, "\t},\n");
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct struct_spec structs[] = {\n");
+
+	for (i = 0; i < s->n_structs; i++) {
+		struct struct_spec *struct_spec = &s->structs[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", struct_spec->name);
+		fprintf(f, "\t\t.fields = struct_%s_fields,\n", struct_spec->name);
+		fprintf(f, "\t\t.n_fields = "
+			"sizeof(struct_%s_fields) / sizeof(struct_%s_fields[0]),\n",
+			struct_spec->name,
+			struct_spec->name);
+		fprintf(f, "\t\t.varbit = %d,\n", struct_spec->varbit);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* header. */
+	fprintf(f, "static struct header_spec headers[] = {\n");
+
+	for (i = 0; i < s->n_headers; i++) {
+		struct header_spec *header_spec = &s->headers[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", header_spec->name);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", header_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* metadata. */
+	fprintf(f, "static struct metadata_spec metadata[] = {\n");
+
+	for (i = 0; i < s->n_metadata; i++) {
+		struct metadata_spec *metadata_spec = &s->metadata[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.struct_type_name = \"%s\",\n", metadata_spec->struct_type_name);
+		fprintf(f, "\t},\n");
+
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* action. */
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *action_%s_initial_instructions[] = {\n",
+			action_spec->name);
+
+		for (j = 0; j < action_spec->n_instructions; j++) {
+			const char *instr = action_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct action_spec actions[] = {\n");
+
+	for (i = 0; i < s->n_actions; i++) {
+		struct action_spec *action_spec = &s->actions[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", action_spec->name);
+
+		if (action_spec->args_struct_type_name)
+			fprintf(f, "\t\t.args_struct_type_name = \"%s\",\n",
+				action_spec->args_struct_type_name);
+		else
+			fprintf(f, "\t\t.args_struct_type_name = NULL,\n");
+
+		fprintf(f, "\t\t.instructions = action_%s_initial_instructions,\n",
+			action_spec->name);
+		fprintf(f, "\t\t.n_instructions = "
+			"sizeof(action_%s_initial_instructions) / "
+			"sizeof(action_%s_initial_instructions[0]),\n",
+			action_spec->name,
+			action_spec->name);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* table. */
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+		uint32_t j;
+
+		/* fields. */
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "static struct rte_swx_match_field_params "
+				"table_%s_fields[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_fields; j++) {
+				struct rte_swx_match_field_params *field =
+					&table_spec->params.fields[j];
+
+				fprintf(f, "\t[%d] = {\n", j);
+				fprintf(f, "\t\t.name = \"%s\",\n", field->name);
+				fprintf(f, "\t\t.match_type = %s,\n",
+					match_type_string_get(field->match_type));
+				fprintf(f, "\t},\n");
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (table_spec->params.action_names && table_spec->params.n_actions) {
+			fprintf(f, "static const char *table_%s_action_names[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				const char *action_name = table_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (table_spec->params.action_is_for_table_entries &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_table_entries[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (table_spec->params.action_is_for_default_entry &&
+		    table_spec->params.n_actions) {
+			fprintf(f, "static int table_%s_action_is_for_default_entry[] = {\n",
+				table_spec->name);
+
+			for (j = 0; j < table_spec->params.n_actions; j++) {
+				int value = table_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct table_spec tables[] = {\n");
+
+	for (i = 0; i < s->n_tables; i++) {
+		struct table_spec *table_spec = &s->tables[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", table_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (table_spec->params.fields && table_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.fields = table_%s_fields,\n", table_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(table_%s_fields) / sizeof(table_%s_fields[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.fields = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (table_spec->params.action_names && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = table_%s_action_names,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (table_spec->params.action_is_for_table_entries && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"table_%s_action_is_for_table_entries,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (table_spec->params.action_is_for_default_entry && table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"table_%s_action_is_for_default_entry,\n",
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (table_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = sizeof(table_%s_action_names) / "
+				"sizeof(table_%s_action_names[0]),\n",
+				table_spec->name,
+				table_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = 0,\n");
+
+		if (table_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				table_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (table_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				table_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			table_spec->params.default_action_is_const);
+		fprintf(f, "\t\t},\n");
+
+		if (table_spec->recommended_table_type_name)
+			fprintf(f, "\t\t.recommended_table_type_name = \"%s\",\n",
+				table_spec->recommended_table_type_name);
+		else
+			fprintf(f, "\t\t.recommended_table_type_name = NULL,\n");
+
+		if (table_spec->args)
+			fprintf(f, "\t\t.args = \"%s\",\n", table_spec->args);
+		else
+			fprintf(f, "\t\t.args = NULL,\n");
+
+		fprintf(f, "\t\t.size = %u,\n", table_spec->size);
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* selector. */
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+		uint32_t j;
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "static const char *selector_%s_field_names[] = {\n",
+				selector_spec->name);
+
+			for (j = 0; j < selector_spec->params.n_selector_fields; j++) {
+				const char *field_name =
+					selector_spec->params.selector_field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct selector_spec selectors[] = {\n");
+
+	for (i = 0; i < s->n_selectors; i++) {
+		struct selector_spec *selector_spec = &s->selectors[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+
+		fprintf(f, "\t\t.name = \"%s\",\n", selector_spec->name);
+		fprintf(f, "\t\t.params = {\n");
+
+		if (selector_spec->params.group_id_field_name)
+			fprintf(f, "\t\t\t.group_id_field_name = \"%s\",\n",
+				selector_spec->params.group_id_field_name);
+		else
+			fprintf(f, "\t\t\t.group_id_field_name = NULL,\n");
+
+		if (selector_spec->params.selector_field_names &&
+		    selector_spec->params.n_selector_fields) {
+			fprintf(f, "\t\t\t.selector_field_names = selector_%s_field_names,\n",
+				selector_spec->name);
+			fprintf(f, "\t\t\t.n_selector_fields = "
+				"sizeof(selector_%s_field_names) / sizeof(selector_%s_field_names[0]),\n",
+				selector_spec->name,
+				selector_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.selector_field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_selector_fields = 0,\n");
+		}
+
+		if (selector_spec->params.member_id_field_name)
+			fprintf(f, "\t\t\t.member_id_field_name = \"%s\",\n",
+				selector_spec->params.member_id_field_name);
+		else
+			fprintf(f, "\t\t\t.member_id_field_name = NULL,\n");
+
+		fprintf(f, "\t\t\t.n_groups_max = %u,\n", selector_spec->params.n_groups_max);
+
+		fprintf(f, "\t\t\t.n_members_per_group_max = %u,\n",
+			selector_spec->params.n_members_per_group_max);
+
+		fprintf(f, "\t\t},\n");
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* learner. */
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+		uint32_t j;
+
+		/* field_names. */
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "static const char *learner_%s_field_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_fields; j++) {
+				const char *field_name = learner_spec->params.field_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, field_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_names. */
+		if (learner_spec->params.action_names && learner_spec->params.n_actions) {
+			fprintf(f, "static const char *learner_%s_action_names[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				const char *action_name = learner_spec->params.action_names[j];
+
+				fprintf(f, "\t[%d] = \"%s\",\n", j, action_name);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_table_entries. */
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_table_entries[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_table_entries[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* action_is_for_default_entry. */
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions) {
+			fprintf(f, "static int learner_%s_action_is_for_default_entry[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->params.n_actions; j++) {
+				int value = learner_spec->params.action_is_for_default_entry[j];
+
+				fprintf(f, "\t[%d] = %d,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+
+		/* timeout. */
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "static uint32_t learner_%s_timeout[] = {\n",
+				learner_spec->name);
+
+			for (j = 0; j < learner_spec->n_timeouts; j++) {
+				uint32_t value = learner_spec->timeout[j];
+
+				fprintf(f, "\t[%d] = %u,\n", j, value);
+			}
+
+			fprintf(f, "};\n\n");
+		}
+	}
+
+	fprintf(f, "static struct learner_spec learners[] = {\n");
+
+	for (i = 0; i < s->n_learners; i++) {
+		struct learner_spec *learner_spec = &s->learners[i];
+
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t\t.name = \"%s\",\n", learner_spec->name);
+
+		fprintf(f, "\t\t.params = {\n");
+
+		if (learner_spec->params.field_names && learner_spec->params.n_fields) {
+			fprintf(f, "\t\t\t.field_names = learner_%s_field_names,\n",
+				learner_spec->name);
+			fprintf(f, "\t\t\t.n_fields = "
+				"sizeof(learner_%s_field_names) / "
+				"sizeof(learner_%s_field_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t\t.field_names = NULL,\n");
+			fprintf(f, "\t\t\t.n_fields = 0,\n");
+		}
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_names = learner_%s_action_names,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_names = NULL,\n");
+
+		if (learner_spec->params.action_is_for_table_entries &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_table_entries = "
+				"learner_%s_action_is_for_table_entries,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_table_entries = NULL,\n");
+
+		if (learner_spec->params.action_is_for_default_entry &&
+		    learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.action_is_for_default_entry = "
+				"learner_%s_action_is_for_default_entry,\n",
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.action_is_for_default_entry = NULL,\n");
+
+		if (learner_spec->params.action_names && learner_spec->params.n_actions)
+			fprintf(f, "\t\t\t.n_actions = "
+				"sizeof(learner_%s_action_names) / sizeof(learner_%s_action_names[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		else
+			fprintf(f, "\t\t\t.n_actions = NULL,\n");
+
+		if (learner_spec->params.default_action_name)
+			fprintf(f, "\t\t\t.default_action_name = \"%s\",\n",
+				learner_spec->params.default_action_name);
+		else
+			fprintf(f, "\t\t\t.default_action_name = NULL,\n");
+
+		if (learner_spec->params.default_action_args)
+			fprintf(f, "\t\t\t.default_action_args = \"%s\",\n",
+				learner_spec->params.default_action_args);
+		else
+			fprintf(f, "\t\t\t.default_action_args = NULL,\n");
+
+		fprintf(f, "\t\t\t.default_action_is_const = %d,\n",
+			learner_spec->params.default_action_is_const);
+
+		fprintf(f, "\t\t},\n");
+
+		fprintf(f, "\t\t.size = %u,\n", learner_spec->size);
+
+		if (learner_spec->timeout && learner_spec->n_timeouts) {
+			fprintf(f, "\t\t.timeout = learner_%s_timeout,\n", learner_spec->name);
+			fprintf(f, "\t\t\t.n_timeouts = "
+				"sizeof(learner_%s_timeout) / sizeof(learner_%s_timeout[0]),\n",
+				learner_spec->name,
+				learner_spec->name);
+		} else {
+			fprintf(f, "\t\t.timeout = NULL,\n");
+			fprintf(f, "\t\t\t.n_timeouts = 0,\n");
+		}
+
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* apply. */
+	for (i = 0; i < s->n_apply; i++) {
+		struct apply_spec *apply_spec = &s->apply[i];
+		uint32_t j;
+
+		fprintf(f, "static const char *apply%u_initial_instructions[] = {\n", i);
+
+		for (j = 0; j < apply_spec->n_instructions; j++) {
+			const char *instr = apply_spec->instructions[j];
+
+			fprintf(f, "\t[%d] = \"%s\",\n", j, instr);
+		}
+
+		fprintf(f, "};\n\n");
+	}
+
+	fprintf(f, "static struct apply_spec apply[] = {\n");
+
+	for (i = 0; i < s->n_apply; i++) {
+		fprintf(f, "\t[%d] = {\n", i);
+		fprintf(f, "\t.instructions = apply%u_initial_instructions,\n", i);
+		fprintf(f, "\t.n_instructions = "
+			"sizeof(apply%u_initial_instructions) / "
+			"sizeof(apply%u_initial_instructions[0]),\n",
+			i,
+			i);
+		fprintf(f, "\t},\n");
+	}
+
+	fprintf(f, "};\n\n");
+
+	/* pipeline. */
+	fprintf(f, "struct pipeline_spec pipeline_spec = {\n");
+	fprintf(f, "\t.extobjs = extobjs,\n");
+	fprintf(f, "\t.structs = structs,\n");
+	fprintf(f, "\t.headers = headers,\n");
+	fprintf(f, "\t.metadata = metadata,\n");
+	fprintf(f, "\t.actions = actions,\n");
+	fprintf(f, "\t.tables = tables,\n");
+	fprintf(f, "\t.selectors = selectors,\n");
+	fprintf(f, "\t.learners = learners,\n");
+	fprintf(f, "\t.regarrays = regarrays,\n");
+	fprintf(f, "\t.metarrays = metarrays,\n");
+	fprintf(f, "\t.apply = apply,\n");
+	fprintf(f, "\t.n_extobjs = sizeof(extobjs) / sizeof(extobjs[0]),\n");
+	fprintf(f, "\t.n_structs = sizeof(structs) / sizeof(structs[0]),\n");
+	fprintf(f, "\t.n_headers = sizeof(headers) / sizeof(headers[0]),\n");
+	fprintf(f, "\t.n_metadata = sizeof(metadata) / sizeof(metadata[0]),\n");
+	fprintf(f, "\t.n_actions = sizeof(actions) / sizeof(actions[0]),\n");
+	fprintf(f, "\t.n_tables = sizeof(tables) / sizeof(tables[0]),\n");
+	fprintf(f, "\t.n_selectors = sizeof(selectors) / sizeof(selectors[0]),\n");
+	fprintf(f, "\t.n_learners = sizeof(learners) / sizeof(learners[0]),\n");
+	fprintf(f, "\t.n_regarrays = sizeof(regarrays) / sizeof(regarrays[0]),\n");
+	fprintf(f, "\t.n_metarrays = sizeof(metarrays) / sizeof(metarrays[0]),\n");
+	fprintf(f, "\t.n_apply = sizeof(apply) / sizeof(apply[0]),\n");
+	fprintf(f, "};\n");
+}
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 4f3a0b5958..707b99ba09 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -206,6 +206,11 @@ struct pipeline_spec {
 
 void
 pipeline_spec_free(struct pipeline_spec *s);
+
+void
+pipeline_spec_codegen(FILE *f,
+		      struct pipeline_spec *s);
+
 struct pipeline_spec *
 pipeline_spec_parse(FILE *spec,
 		    uint32_t *err_line,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 06/17] pipeline: add support for pipeline I/O specification
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (4 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
                     ` (11 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add specification data structure and API for the pipeline I/O ports
and related pipeline configuration such as packet mirroring.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline_spec.c | 852 +++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline_spec.h |  58 ++
 2 files changed, 910 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index bf21fe17ba..f34803793d 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -9,6 +9,12 @@
 #include <errno.h>
 
 #include <rte_common.h>
+#include <rte_mempool.h>
+
+#include <rte_swx_port_ethdev.h>
+#include <rte_swx_port_ring.h>
+#include <rte_swx_port_source_sink.h>
+#include <rte_swx_port_fd.h>
 
 #include "rte_swx_pipeline_spec.h"
 
@@ -3566,3 +3572,849 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
 	pipeline_spec_free(s);
 	return status;
 }
+
+static void
+port_in_params_free(void *params, const char *port_type)
+{
+	uintptr_t dev_name;
+
+	if (!params || !port_type)
+		return;
+
+	if (!strcmp(port_type, "ethdev")) {
+		struct rte_swx_port_ethdev_reader_params *p = params;
+
+		dev_name = (uintptr_t)p->dev_name;
+	} else if (!strcmp(port_type, "ring")) {
+		struct rte_swx_port_ring_reader_params *p = params;
+
+		dev_name = (uintptr_t)p->name;
+	} else if (!strcmp(port_type, "source")) {
+		struct rte_swx_port_source_params *p = params;
+
+		dev_name = (uintptr_t)p->file_name;
+	} else
+		dev_name = (uintptr_t)NULL;
+
+	free((void *)dev_name);
+	free(params);
+}
+
+static void
+port_out_params_free(void *params, const char *port_type)
+{
+	uintptr_t dev_name;
+
+	if (!params || !port_type)
+		return;
+
+	if (!strcmp(port_type, "ethdev")) {
+		struct rte_swx_port_ethdev_writer_params *p = params;
+
+		dev_name = (uintptr_t)p->dev_name;
+	} else if (!strcmp(port_type, "ring")) {
+		struct rte_swx_port_ring_writer_params *p = params;
+
+		dev_name = (uintptr_t)p->name;
+	} else if (!strcmp(port_type, "sink")) {
+		struct rte_swx_port_sink_params *p = params;
+
+		dev_name = (uintptr_t)p->file_name;
+	} else
+		dev_name = (uintptr_t)NULL;
+
+	free((void *)dev_name);
+	free(params);
+}
+
+void
+pipeline_iospec_free(struct pipeline_iospec *s)
+{
+	uint32_t i;
+
+	if (!s)
+		return;
+
+	/* Input ports. */
+	for (i = 0; i < s->n_ports_in; i++) {
+		uintptr_t name = (uintptr_t)s->port_in_type[i];
+
+		port_in_params_free(s->port_in_params[i], s->port_in_type[i]);
+		free((void *)name);
+	}
+
+	free(s->port_in_type);
+	free(s->port_in_params);
+
+	/* Output ports. */
+	for (i = 0; i < s->n_ports_out; i++) {
+		uintptr_t name = (uintptr_t)s->port_out_type[i];
+
+		port_out_params_free(s->port_out_params[i], s->port_out_type[i]);
+		free((void *)name);
+	}
+
+	free(s->port_out_type);
+	free(s->port_out_params);
+
+	free(s);
+}
+
+static int
+mirroring_parse(struct rte_swx_pipeline_mirroring_params *p,
+		char **tokens,
+		uint32_t n_tokens,
+		const char **err_msg)
+{
+	char *token;
+
+	if ((n_tokens != 4) || strcmp(tokens[0], "slots") || strcmp(tokens[2], "sessions")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return -EINVAL;
+	}
+
+	/* <n_slots>. */
+	token = tokens[1];
+	p->n_slots = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_slots> parameter.";
+		return -EINVAL;
+	}
+
+	/* <n_sessions>. */
+	token = tokens[3];
+	p->n_sessions = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_sessions> parameter.";
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+port_in_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ethdev_reader_params *p = NULL;
+	char *token, *dev_name = NULL;
+	uint32_t queue_id, burst_size;
+
+	if ((n_tokens != 5) || strcmp(tokens[1], "rxq") || strcmp(tokens[3], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <queue_id>. */
+	token = tokens[2];
+	queue_id = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <queue_id> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[4];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	dev_name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ethdev_reader_params));
+	if (!dev_name || !p) {
+		free(dev_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->dev_name = dev_name;
+	p->queue_id = queue_id;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_in_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ring_reader_params *p = NULL;
+	char *token, *name = NULL;
+	uint32_t burst_size;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ring_reader_params));
+	if (!name || !p) {
+		free(name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->name = name;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_in_source_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_source_params *p = NULL;
+	struct rte_mempool *pool = NULL;
+	char *token, *file_name = NULL;
+	uint32_t n_loops, n_pkts_max;
+
+	if ((n_tokens != 8) ||
+	    strcmp(tokens[0], "mempool") ||
+	    strcmp(tokens[2], "file") ||
+	    strcmp(tokens[4], "loop") ||
+	    strcmp(tokens[6], "packets")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <mempool_name>. */
+	pool = rte_mempool_lookup(tokens[1]);
+	if (!pool) {
+		if (err_msg)
+			*err_msg = "Invalid <mempool_name> parameter.";
+		return NULL;
+	}
+
+	/* <n_loops>. */
+	token = tokens[5];
+	n_loops = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_loops> parameter.";
+		return NULL;
+	}
+
+	/* <n_pkts_max>. */
+	token = tokens[7];
+	n_pkts_max = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <n_pkts_max> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	file_name = strdup(tokens[3]);
+	p = malloc(sizeof(struct rte_swx_port_source_params));
+	if (!file_name || !p) {
+		free(file_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->pool = pool;
+	p->file_name = file_name;
+	p->n_loops = n_loops;
+	p->n_pkts_max = n_pkts_max;
+
+	return p;
+}
+
+static void *
+port_in_fd_parse(char **tokens,
+		 uint32_t n_tokens,
+		 const char **err_msg)
+{
+	struct rte_swx_port_fd_reader_params *p = NULL;
+	struct rte_mempool *mempool = NULL;
+	char *token;
+	uint32_t mtu, burst_size;
+	int fd;
+
+	if ((n_tokens != 7) ||
+	    strcmp(tokens[1], "mtu") ||
+	    strcmp(tokens[3], "mempool") ||
+	    strcmp(tokens[5], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <file_descriptor>. */
+	token = tokens[0];
+	fd = strtol(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <file_descriptor> parameter.";
+		return NULL;
+	}
+
+	/* <mtu>. */
+	token = tokens[2];
+	mtu = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <mtu> parameter.";
+		return NULL;
+	}
+
+	/* <mempool_name>. */
+	mempool = rte_mempool_lookup(tokens[4]);
+	if (!mempool) {
+		if (err_msg)
+			*err_msg = "Invalid <mempool_name> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[6];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	p = malloc(sizeof(struct rte_swx_port_fd_reader_params));
+	if (!p) {
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->fd = fd;
+	p->mtu = mtu;
+	p->mempool = mempool;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ethdev_writer_params *p = NULL;
+	char *token, *dev_name = NULL;
+	uint32_t queue_id, burst_size;
+
+	if ((n_tokens != 5) || strcmp(tokens[1], "txq") || strcmp(tokens[3], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <queue_id>. */
+	token = tokens[2];
+	queue_id = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <queue_id> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[4];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	dev_name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ethdev_writer_params));
+	if (!dev_name || !p) {
+		free(dev_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->dev_name = dev_name;
+	p->queue_id = queue_id;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_ring_writer_params *p = NULL;
+	char *token, *name = NULL;
+	uint32_t burst_size;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	name = strdup(tokens[0]);
+	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
+	if (!name || !p) {
+		free(name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->name = name;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+static void *
+port_out_sink_parse(char **tokens, uint32_t n_tokens, const char **err_msg)
+{
+	struct rte_swx_port_sink_params *p = NULL;
+	char *file_name = NULL;
+	int file_name_valid = 0;
+
+	if ((n_tokens != 2) || strcmp(tokens[0], "file")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	if (strcmp(tokens[1], "none")) {
+		file_name_valid = 1;
+		file_name = strdup(tokens[1]);
+	}
+
+	p = malloc(sizeof(struct rte_swx_port_ring_writer_params));
+	if ((file_name_valid && !file_name) || !p) {
+		free(file_name);
+		free(p);
+
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->file_name = file_name;
+
+	return p;
+}
+
+static void *
+port_out_fd_parse(char **tokens,
+		  uint32_t n_tokens,
+		  const char **err_msg)
+{
+	struct rte_swx_port_fd_writer_params *p = NULL;
+	char *token;
+	uint32_t burst_size;
+	int fd;
+
+	if ((n_tokens != 3) || strcmp(tokens[1], "bsz")) {
+		if (err_msg)
+			*err_msg = "Invalid statement.";
+		return NULL;
+	}
+
+	/* <file_descriptor>. */
+	token = tokens[0];
+	fd = strtol(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <file_descriptor> parameter.";
+		return NULL;
+	}
+
+	/* <burst_size>. */
+	token = tokens[2];
+	burst_size = strtoul(token, &token, 0);
+	if (token[0]) {
+		if (err_msg)
+			*err_msg = "Invalid <burst_size> parameter.";
+		return NULL;
+	}
+
+	/* Memory allocation. */
+	p = malloc(sizeof(struct rte_swx_port_fd_writer_params));
+	if (!p) {
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		return NULL;
+	}
+
+	/* Initialization. */
+	p->fd = fd;
+	p->burst_size = burst_size;
+
+	return p;
+}
+
+struct pipeline_iospec *
+pipeline_iospec_parse(FILE *spec,
+		      uint32_t *err_line,
+		      const char **err_msg)
+{
+	struct pipeline_iospec *s = NULL;
+	uint32_t n_lines = 0;
+
+	/* Check the input arguments. */
+	if (!spec) {
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		goto error;
+	}
+
+	/* Memory allocation. */
+	s = calloc(sizeof(struct pipeline_iospec), 1);
+	if (!s) {
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		goto error;
+	}
+
+	/* Initialize with the default values. */
+	s->mirroring_params.n_slots = RTE_SWX_PACKET_MIRRORING_SLOTS_DEFAULT;
+	s->mirroring_params.n_sessions = RTE_SWX_PACKET_MIRRORING_SESSIONS_DEFAULT;
+
+	for (n_lines = 1; ; n_lines++) {
+		char line[MAX_LINE_LENGTH];
+		char *tokens[MAX_TOKENS], *ptr = line;
+		uint32_t n_tokens = 0;
+
+		/* Read next line. */
+		if (!fgets(line, sizeof(line), spec))
+			break;
+
+		/* Parse the line into tokens. */
+		for ( ; ; ) {
+			char *token;
+
+			/* Get token. */
+			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
+			if (!token)
+				break;
+
+			/* Handle comments. */
+			if ((token[0] == '#') ||
+			    (token[0] == ';') ||
+			    ((token[0] == '/') && (token[1] == '/'))) {
+				break;
+			}
+
+			/* Handle excessively long lines. */
+			if (n_tokens >= RTE_DIM(tokens)) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Too many tokens.";
+				goto error;
+			}
+
+			/* Handle excessively long tokens. */
+			if (strnlen(token, RTE_SWX_NAME_SIZE) >=
+			    RTE_SWX_NAME_SIZE) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Token too big.";
+				goto error;
+			}
+
+			/* Save token. */
+			tokens[n_tokens] = token;
+			n_tokens++;
+		}
+
+		/* Handle empty lines. */
+		if (!n_tokens)
+			continue;
+
+		/* mirroring. */
+		if ((n_tokens >= 1) && !strcmp(tokens[0], "mirroring")) {
+			int status = 0;
+
+			status = mirroring_parse(&s->mirroring_params,
+						 &tokens[1],
+						 n_tokens - 1,
+						 err_msg);
+			if (status) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			continue;
+		}
+
+		/* port in. */
+		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "in")) {
+			char *token = tokens[2];
+			uint32_t *new_id = NULL;
+			const char **new_type = NULL, *port_type = NULL;
+			void **new_params = NULL, *p = NULL;
+			uint32_t port_id;
+
+			/* <port_id>. */
+			port_id = strtoul(token, &token, 0);
+			if (token[0]) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Invalid port ID.";
+				goto error;
+			}
+
+			/* <port_type>. */
+			if (!strcmp(tokens[3], "ethdev"))
+				p = port_in_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "ring"))
+				p = port_in_ring_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "source"))
+				p = port_in_source_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "fd"))
+				p = port_in_fd_parse(&tokens[4], n_tokens - 4, err_msg);
+			else {
+				p = NULL;
+				if (err_msg)
+					*err_msg = "Invalid port type.";
+			}
+
+			if (!p) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			/* New port. */
+			port_type = strdup(tokens[3]);
+			new_id = realloc(s->port_in_id,
+					 (s->n_ports_in + 1) * sizeof(uint32_t));
+			new_type = realloc(s->port_in_type,
+					   (s->n_ports_in + 1) * sizeof(char *));
+			new_params = realloc(s->port_in_params,
+					     (s->n_ports_in + 1) * sizeof(void *));
+			if (!port_type || !new_id || !new_type || !new_params) {
+				uintptr_t pt = (uintptr_t)port_type;
+
+				port_in_params_free(p, tokens[3]);
+				free((void *)pt);
+				free(new_id);
+				free(new_type);
+				free(new_params);
+
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Memory allocation failed.";
+				goto error;
+			}
+
+			s->port_in_id = new_id;
+			s->port_in_type = new_type;
+			s->port_in_params = new_params;
+
+			s->port_in_id[s->n_ports_in] = port_id;
+			s->port_in_type[s->n_ports_in] = port_type;
+			s->port_in_params[s->n_ports_in] = p;
+			s->n_ports_in++;
+
+			continue;
+		}
+
+		/* port out. */
+		if ((n_tokens >= 4) && !strcmp(tokens[0], "port") && !strcmp(tokens[1], "out")) {
+			char *token = tokens[2];
+			uint32_t *new_id = NULL;
+			const char **new_type = NULL, *port_type = NULL;
+			void **new_params = NULL, *p = NULL;
+			uint32_t port_id;
+
+			/* <port_id>. */
+			port_id = strtoul(token, &token, 0);
+			if (token[0]) {
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Invalid port ID.";
+				goto error;
+			}
+
+			/* <port_type>. */
+			if (!strcmp(tokens[3], "ethdev"))
+				p = port_out_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "ring"))
+				p = port_out_ring_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "sink"))
+				p = port_out_sink_parse(&tokens[4], n_tokens - 4, err_msg);
+			else if (!strcmp(tokens[3], "fd"))
+				p = port_out_fd_parse(&tokens[4], n_tokens - 4, err_msg);
+			else {
+				p = NULL;
+				if (err_msg)
+					*err_msg = "Invalid port type.";
+			}
+
+			if (!p) {
+				if (err_line)
+					*err_line = n_lines;
+				goto error;
+			}
+
+			/* New port. */
+			port_type = strdup(tokens[3]);
+			new_id = realloc(s->port_out_id,
+					 (s->n_ports_out + 1) * sizeof(uint32_t));
+			new_type = realloc(s->port_out_type,
+					   (s->n_ports_out + 1) * sizeof(char *));
+			new_params = realloc(s->port_out_params,
+					     (s->n_ports_out + 1) * sizeof(void *));
+			if (!port_type || !new_id || !new_type || !new_params) {
+				uintptr_t pt = (uintptr_t)port_type;
+
+				port_out_params_free(p, tokens[3]);
+				free((void *)pt);
+				free(new_id);
+				free(new_type);
+				free(new_params);
+
+				if (err_line)
+					*err_line = n_lines;
+				if (err_msg)
+					*err_msg = "Memory allocation failed.";
+				goto error;
+			}
+
+			s->port_out_id = new_id;
+			s->port_out_type = new_type;
+			s->port_out_params = new_params;
+
+			s->port_out_id[s->n_ports_out] = port_id;
+			s->port_out_type[s->n_ports_out] = port_type;
+			s->port_out_params[s->n_ports_out] = p;
+			s->n_ports_out++;
+
+			continue;
+		}
+
+		/* Anything else. */
+		if (err_line)
+			*err_line = n_lines;
+		if (err_msg)
+			*err_msg = "Unknown I/O statement.";
+		goto error;
+	}
+
+	return s;
+
+error:
+	pipeline_iospec_free(s);
+
+	return NULL;
+}
+
+int
+pipeline_iospec_configure(struct rte_swx_pipeline *p,
+			  struct pipeline_iospec *s,
+			  const char **err_msg)
+{
+	uint32_t i;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!p || !s) {
+		if (err_msg)
+			*err_msg = "Invalid input argument";
+		return -EINVAL;
+	}
+
+	/* Mirroring. */
+	status = rte_swx_pipeline_mirroring_config(p, &s->mirroring_params);
+	if (status) {
+		if (err_msg)
+			*err_msg = "Pipeline mirroring configuration error.";
+		return status;
+	}
+
+	/* Input ports. */
+	for (i = 0; i < s->n_ports_in; i++) {
+		status = rte_swx_pipeline_port_in_config(p,
+							 i,
+							 s->port_in_type[i],
+							 s->port_in_params[i]);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline input port configuration error.";
+			return status;
+		}
+	}
+
+	/* Output ports. */
+	for (i = 0; i < s->n_ports_out; i++) {
+		status = rte_swx_pipeline_port_out_config(p,
+							  i,
+							  s->port_out_type[i],
+							  s->port_out_params[i]);
+		if (status) {
+			if (err_msg)
+				*err_msg = "Pipeline output port configuration error.";
+			return status;
+		}
+	}
+
+	return 0;
+}
diff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h
index 707b99ba09..62ac4ecfc4 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.h
+++ b/lib/pipeline/rte_swx_pipeline_spec.h
@@ -1,6 +1,13 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright(c) 2022 Intel Corporation
  */
+#ifndef __INCLUDE_RTE_SWX_PIPELINE_SPEC_H__
+#define __INCLUDE_RTE_SWX_PIPELINE_SPEC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <stdint.h>
 #include <stdio.h>
 
@@ -204,6 +211,38 @@ struct pipeline_spec {
 	uint32_t n_apply;
 };
 
+/*
+ * Mirroring:
+ *      mirroring slots <n_slots> sessions <n_sessions>
+ *
+ * Input ports:
+ *      port in <port_id> ethdev <ethdev_name> rxq <queue_id> bsz <burst_size>
+ *      port in <port_id> ring <ring_name> bsz <burst_size>
+ *      port in <port_id> source mempool <mempool_name> file <file_name> loop <n_loops>
+ *                               packets <n_pkts_max>
+ *      port in <port_id> fd <file_descriptor> mtu <mtu> mempool <mempool_name> bsz <burst_size>
+ *
+ * Output ports:
+ *      port out <port_id> ethdev <ethdev_name> txq <queue_id> bsz <burst_size>
+ *      port out <port_id> ring <ring_name> bsz <burst_size>
+ *      port out <port_id> sink file <file_name> | none
+ *      port out <port_id> fd <file_descriptor> bsz <burst_size>
+ */
+struct pipeline_iospec {
+	struct rte_swx_pipeline_mirroring_params mirroring_params;
+
+	uint32_t *port_in_id;
+	const char **port_in_type;
+	void **port_in_params;
+
+	uint32_t *port_out_id;
+	const char **port_out_type;
+	void **port_out_params;
+
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+};
+
 void
 pipeline_spec_free(struct pipeline_spec *s);
 
@@ -220,3 +259,22 @@ int
 pipeline_spec_configure(struct rte_swx_pipeline *p,
 			struct pipeline_spec *s,
 			const char **err_msg);
+
+void
+pipeline_iospec_free(struct pipeline_iospec *s);
+
+struct pipeline_iospec *
+pipeline_iospec_parse(FILE *spec,
+		      uint32_t *err_line,
+		      const char **err_msg);
+
+int
+pipeline_iospec_configure(struct rte_swx_pipeline *p,
+			  struct pipeline_iospec *s,
+			  const char **err_msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 07/17] pipeline: add API for pipeline code generation
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (5 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
                     ` (10 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the C code generation for the pipeline was hidden under
the hood; now, we make this an explicit API operation. Besides the
functions for the pipeline actions and the pipeline instructions,
the generated C source code now includes the pipeline specification
structure required for the pipeline configuration operations.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 lib/pipeline/rte_swx_pipeline.c | 94 +++++++++++++++++++++++++++++++++
 lib/pipeline/rte_swx_pipeline.h | 25 +++++++++
 lib/pipeline/version.map        |  1 +
 3 files changed, 120 insertions(+)

diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index c8ccded4f8..dd5f7107fa 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -20,6 +20,7 @@
 #include <rte_swx_table_wm.h>
 
 #include "rte_swx_pipeline_internal.h"
+#include "rte_swx_pipeline_spec.h"
 
 #define CHECK(condition, err_code)                                             \
 do {                                                                           \
@@ -13581,3 +13582,96 @@ pipeline_compile(struct rte_swx_pipeline *p)
 
 	return status;
 }
+
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg)
+
+{
+	struct rte_swx_pipeline *p = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!spec_file || !code_file) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Invalid input argument.";
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration. */
+	s = pipeline_spec_parse(spec_file, err_line, err_msg);
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	status = rte_swx_pipeline_config(&p, NULL, 0);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Pipeline configuration error.";
+		goto free;
+	}
+
+	status = pipeline_spec_configure(p, s, err_msg);
+	if (status) {
+		if (err_line)
+			*err_line = 0;
+		goto free;
+	}
+
+	/*
+	 * Pipeline code generation.
+	 */
+
+	/* Instruction Group List (IGL) computation: the pipeline configuration must be done first,
+	 * but there is no need for the pipeline build to be done as well.
+	 */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		if (err_line)
+			*err_line = 0;
+		if (err_msg)
+			*err_msg = "Memory allocation failed.";
+		status = -ENOMEM;
+		goto free;
+	}
+
+	/* Header file inclusion. */
+	fprintf(code_file, "#include \"rte_swx_pipeline_internal.h\"\n");
+	fprintf(code_file, "#include \"rte_swx_pipeline_spec.h\"\n\n");
+
+	/* Code generation for the pipeline specification. */
+	pipeline_spec_codegen(code_file, s);
+	fprintf(code_file, "\n");
+
+	/* Code generation for the action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		fprintf(code_file, "/**\n * Action %s\n */\n\n", a->name);
+
+		action_data_codegen(a, code_file);
+		fprintf(code_file, "\n");
+
+		action_instr_codegen(a, code_file);
+		fprintf(code_file, "\n");
+	}
+
+	/* Code generation for the pipeline instructions. */
+	instruction_group_list_codegen(igl, p, code_file);
+
+free:
+	instruction_group_list_free(igl);
+	rte_swx_pipeline_free(p);
+	pipeline_spec_free(s);
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index ef50a0fa70..724607b87c 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -957,6 +957,31 @@ __rte_experimental
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p);
 
+/**
+ * Pipeline C code generate based on input specification file
+ *
+ * @param[in] spec_file
+ *   Pipeline specification file (.spec) provided as input.
+ * @param[in] code_file
+ *   Pipeline C language file (.c) to be generated.
+ * @param[out] err_line
+ *   In case of error and non-NULL, the line number within the *spec* file where
+ *   the error occurred. The first line number in the file is 1.
+ * @param[out] err_msg
+ *   In case of error and non-NULL, the error message.
+ * @return
+ *   0 on success or the following error codes otherwise:
+ *   -EINVAL: Invalid argument;
+ *   -ENOMEM: Not enough space/cannot allocate memory;
+ *   -EEXIST: Resource with the same name already exists.
+ */
+__rte_experimental
+int
+rte_swx_pipeline_codegen(FILE *spec_file,
+			 FILE *code_file,
+			 uint32_t *err_line,
+			 const char **err_msg);
+
 /**
  * Pipeline build from specification file
  *
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 50029aadcf..8d95005a5b 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -148,5 +148,6 @@ EXPERIMENTAL {
 
 	#added in 22.11
 	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_codegen;
 	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 08/17] pipeline: add API for shared library-based pipeline build
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (6 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
                     ` (9 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Previously, the pipeline build operation was done based on the
specification file (typically produced by the P4 compiler), then the C
code with optimized functions for the pipeline actions and
instructions was generated, built into a shared object library, loaded
and installed into the pipeline in a completely hardcoded and
non-customizable way.

Now, this process is split into three explicit stages:
i) code generation (specification file -> C file);
ii) code build (C file -> shared object library);
iii) code installation (library load into the pipeline).

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c              |  85 ++++---
 lib/pipeline/rte_swx_pipeline.c      | 319 +++++++++++----------------
 lib/pipeline/rte_swx_pipeline.h      |  38 ++--
 lib/pipeline/rte_swx_pipeline_spec.c |  51 -----
 lib/pipeline/version.map             |   2 +-
 5 files changed, 208 insertions(+), 287 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index ad553f19ab..f0285675b3 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -984,55 +984,88 @@ cmd_pipeline_port_out(char **tokens,
 }
 
 static const char cmd_pipeline_build_help[] =
-"pipeline <pipeline_name> build <spec_file>\n";
+"pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
 static void
 cmd_pipeline_build(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p = NULL;
-	FILE *spec = NULL;
-	uint32_t err_line;
-	const char *err_msg;
-	int status;
+	struct rte_swx_pipeline *p = NULL;
+	struct rte_swx_ctl_pipeline *ctl = NULL;
+	char *pipeline_name, *lib_file_name, *iospec_file_name;
+	FILE *iospec_file = NULL;
+	uint32_t numa_node = 0;
+	int status = 0;
 
-	if (n_tokens != 4) {
+	/* Parsing. */
+	if (n_tokens != 9) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "build")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "build");
 		return;
 	}
 
-	spec = fopen(tokens[3], "r");
-	if (!spec) {
-		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
+	if (strcmp(tokens[3], "lib")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "lib");
 		return;
 	}
 
-	status = rte_swx_pipeline_build_from_spec(p->p,
-		spec,
-		&err_line,
-		&err_msg);
-	fclose(spec);
-	if (status) {
-		snprintf(out, out_size, "Error %d at line %u: %s\n.",
-			status, err_line, err_msg);
+	lib_file_name = tokens[4];
+
+	if (strcmp(tokens[5], "io")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "io");
 		return;
 	}
 
-	p->ctl = rte_swx_ctl_pipeline_create(p->p);
-	if (!p->ctl) {
-		snprintf(out, out_size, "Pipeline control create failed.");
-		rte_swx_pipeline_free(p->p);
+	iospec_file_name = tokens[6];
+
+	if (strcmp(tokens[7], "numa")) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa");
 		return;
 	}
+
+	if (parser_read_uint32(&numa_node, tokens[8])) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "numa_node");
+		return;
+	}
+
+	/* I/O spec file open. */
+	iospec_file = fopen(iospec_file_name, "r");
+	if (!iospec_file) {
+		snprintf(out, out_size, "Cannot open file \"%s\".\n", iospec_file_name);
+		return;
+	}
+
+	status = rte_swx_pipeline_build_from_lib(&p,
+						 pipeline_name,
+						 lib_file_name,
+						 iospec_file,
+						 (int)numa_node);
+	if (status) {
+		snprintf(out, out_size, "Pipeline build failed (%d).", status);
+		goto free;
+	}
+
+	ctl = rte_swx_ctl_pipeline_create(p);
+	if (!ctl) {
+		snprintf(out, out_size, "Pipeline control create failed.");
+		goto free;
+	}
+
+free:
+	if (status)
+		rte_swx_pipeline_free(p);
+
+	if (iospec_file)
+		fclose(iospec_file);
 }
 
 static void
diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index dd5f7107fa..12e156b00b 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -9911,9 +9911,6 @@ rte_swx_pipeline_instructions_config(struct rte_swx_pipeline *p,
 	return 0;
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p);
-
 int
 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 {
@@ -10003,8 +10000,6 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p)
 
 	p->build_done = 1;
 
-	pipeline_compile(p);
-
 	return 0;
 
 error:
@@ -13327,160 +13322,6 @@ instruction_group_list_custom_instructions_count(struct instruction_group_list *
 	return n_custom_instr;
 }
 
-static int
-pipeline_codegen(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	FILE *f = NULL;
-
-	/* Create the .c file. */
-	f = fopen("/tmp/pipeline.c", "w");
-	if (!f)
-		return -EIO;
-
-	/* Include the .h file. */
-	fprintf(f, "#include \"rte_swx_pipeline_internal.h\"\n");
-
-	/* Add the code for each action. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		fprintf(f, "/**\n * Action %s\n */\n\n", a->name);
-
-		action_data_codegen(a, f);
-
-		fprintf(f, "\n");
-
-		action_instr_codegen(a, f);
-
-		fprintf(f, "\n");
-	}
-
-	/* Add the pipeline code. */
-	instruction_group_list_codegen(igl, p, f);
-
-	/* Close the .c file. */
-	fclose(f);
-
-	return 0;
-}
-
-#ifndef RTE_SWX_PIPELINE_CMD_MAX_SIZE
-#define RTE_SWX_PIPELINE_CMD_MAX_SIZE 4096
-#endif
-
-static int
-pipeline_libload(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
-{
-	struct action *a;
-	struct instruction_group *g;
-	char *dir_in, *buffer = NULL;
-	const char *dir_out;
-	int status = 0;
-
-	/* Get the environment variables. */
-	dir_in = getenv("RTE_INSTALL_DIR");
-	if (!dir_in) {
-		status = -EINVAL;
-		goto free;
-	}
-
-	dir_out = "/tmp";
-
-	/* Memory allocation for the command buffer. */
-	buffer = malloc(RTE_SWX_PIPELINE_CMD_MAX_SIZE);
-	if (!buffer) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s/pipeline.o %s/pipeline.c "
-		 "-I %s/lib/pipeline "
-		 "-I %s/lib/eal/include "
-		 "-I %s/lib/eal/x86/include "
-		 "-I %s/lib/eal/include/generic "
-		 "-I %s/lib/meter "
-		 "-I %s/lib/port "
-		 "-I %s/lib/table "
-		 "-I %s/lib/pipeline "
-		 "-I %s/config "
-		 "-I %s/build "
-		 "-I %s/lib/eal/linux/include "
-		 ">%s/pipeline.log 2>&1 "
-		 "&& "
-		 "gcc -shared %s/pipeline.o -o %s/libpipeline.so "
-		 ">>%s/pipeline.log 2>&1",
-		 dir_out,
-		 dir_out,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_in,
-		 dir_out,
-		 dir_out,
-		 dir_out,
-		 dir_out);
-
-	/* Build the shared object library. */
-	status = system(buffer);
-	if (status)
-		goto free;
-
-	/* Open library. */
-	snprintf(buffer,
-		 RTE_SWX_PIPELINE_CMD_MAX_SIZE,
-		 "%s/libpipeline.so",
-		 dir_out);
-
-	p->lib = dlopen(buffer, RTLD_LAZY);
-	if (!p->lib) {
-		status = -EIO;
-		goto free;
-	}
-
-	/* Get the action function symbols. */
-	TAILQ_FOREACH(a, &p->actions, node) {
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "action_%s_run", a->name);
-
-		p->action_funcs[a->id] = dlsym(p->lib, buffer);
-		if (!p->action_funcs[a->id]) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-	/* Get the pipeline function symbols. */
-	TAILQ_FOREACH(g, igl, node) {
-		if (g->first_instr_id == g->last_instr_id)
-			continue;
-
-		snprintf(buffer, RTE_SWX_PIPELINE_CMD_MAX_SIZE, "pipeline_func_%u", g->group_id);
-
-		g->func = dlsym(p->lib, buffer);
-		if (!g->func) {
-			status = -EINVAL;
-			goto free;
-		}
-	}
-
-free:
-	if (status && p->lib) {
-		dlclose(p->lib);
-		p->lib = NULL;
-	}
-
-	free(buffer);
-
-	return status;
-}
-
 static int
 pipeline_adjust_check(struct rte_swx_pipeline *p __rte_unused,
 		      struct instruction_group_list *igl)
@@ -13548,41 +13389,6 @@ pipeline_adjust(struct rte_swx_pipeline *p, struct instruction_group_list *igl)
 	instr_jmp_resolve(p->instructions, p->instruction_data, p->n_instructions);
 }
 
-static int
-pipeline_compile(struct rte_swx_pipeline *p)
-{
-	struct instruction_group_list *igl = NULL;
-	int status = 0;
-
-	igl = instruction_group_list_create(p);
-	if (!igl) {
-		status = -ENOMEM;
-		goto free;
-	}
-
-	/* Code generation. */
-	status = pipeline_codegen(p, igl);
-	if (status)
-		goto free;
-
-	/* Build and load the shared object library. */
-	status = pipeline_libload(p, igl);
-	if (status)
-		goto free;
-
-	/* Adjust instructions. */
-	status = pipeline_adjust_check(p, igl);
-	if (status)
-		goto free;
-
-	pipeline_adjust(p, igl);
-
-free:
-	instruction_group_list_free(igl);
-
-	return status;
-}
-
 int
 rte_swx_pipeline_codegen(FILE *spec_file,
 			 FILE *code_file,
@@ -13675,3 +13481,128 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 
 	return status;
 }
+
+int
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline **pipeline,
+				const char *name,
+				const char *lib_file_name,
+				FILE *iospec_file,
+				int numa_node)
+{
+	struct rte_swx_pipeline *p = NULL;
+	void *lib = NULL;
+	struct pipeline_iospec *sio = NULL;
+	struct pipeline_spec *s = NULL;
+	struct instruction_group_list *igl = NULL;
+	struct action *a;
+	struct instruction_group *g;
+	int status = 0;
+
+	/* Check input arguments. */
+	if (!pipeline ||
+	    !name ||
+	    !name[0] ||
+	    !lib_file_name ||
+	    !lib_file_name[0] ||
+	    !iospec_file) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Open the library. */
+	lib = dlopen(lib_file_name, RTLD_LAZY);
+	if (!lib) {
+		status = -EIO;
+		goto free;
+	}
+
+	/* Get the pipeline specification structures. */
+	s = dlsym(lib, "pipeline_spec");
+	if (!s) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	sio = pipeline_iospec_parse(iospec_file, NULL, NULL);
+	if (!sio) {
+		status = -EINVAL;
+		goto free;
+	}
+
+	/* Pipeline configuration based on the specification structures. */
+	status = rte_swx_pipeline_config(&p, name, numa_node);
+	if (status)
+		goto free;
+
+	status = pipeline_iospec_configure(p, sio, NULL);
+	if (status)
+		goto free;
+
+	status = pipeline_spec_configure(p, s, NULL);
+	if (status)
+		goto free;
+
+	/* Pipeline build. */
+	status = rte_swx_pipeline_build(p);
+	if (status)
+		goto free;
+
+	/* Action instructions. */
+	TAILQ_FOREACH(a, &p->actions, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		snprintf(name, sizeof(name), "action_%s_run", a->name);
+
+		p->action_funcs[a->id] = dlsym(lib, name);
+		if (!p->action_funcs[a->id]) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	/* Pipeline instructions. */
+	igl = instruction_group_list_create(p);
+	if (!igl) {
+		status = -ENOMEM;
+		goto free;
+	}
+
+	TAILQ_FOREACH(g, igl, node) {
+		char name[RTE_SWX_NAME_SIZE * 2];
+
+		if (g->first_instr_id == g->last_instr_id)
+			continue;
+
+		snprintf(name, sizeof(name), "pipeline_func_%u", g->group_id);
+
+		g->func = dlsym(lib, name);
+		if (!g->func) {
+			status = -EINVAL;
+			goto free;
+		}
+	}
+
+	status = pipeline_adjust_check(p, igl);
+	if (status)
+		goto free;
+
+	pipeline_adjust(p, igl);
+
+	p->lib = lib;
+
+	*pipeline = p;
+
+free:
+	instruction_group_list_free(igl);
+
+	pipeline_iospec_free(sio);
+
+	if (status) {
+		rte_swx_pipeline_free(p);
+
+		if (lib)
+			dlclose(lib);
+	}
+
+	return status;
+}
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index 724607b87c..9c629d4118 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -983,30 +983,38 @@ rte_swx_pipeline_codegen(FILE *spec_file,
 			 const char **err_msg);
 
 /**
- * Pipeline build from specification file
+ * Pipeline build from shared object library
  *
- * @param[in] p
- *   Pipeline handle.
- * @param[in] spec
- *   Pipeline specification file.
- * @param[out] err_line
- *   In case of error and non-NULL, the line number within the *spec* file where
- *   the error occurred. The first line number in the file is 1.
- * @param[out] err_msg
- *   In case of error and non-NULL, the error message.
+ * The shared object library must be built from the C language source code file
+ * previously generated by the rte_swx_pipeline_codegen() API function.
+ *
+ * The pipeline I/O specification file defines the I/O ports of the pipeline.
+ *
+ * @param[out] p
+ *   Pipeline handle. Must point to valid memory. Contains valid pipeline handle
+ *   when the function returns successfully.
+ * @param[in] name
+ *   Pipeline unique name.
+ * @param[in] lib_file_name
+ *   Shared object library file name.
+ * @param[in] iospec_file
+ *   Pipeline I/O specification file.
+ * @param[in] numa_node
+ *   Non-Uniform Memory Access (NUMA) node.
  * @return
  *   0 on success or the following error codes otherwise:
  *   -EINVAL: Invalid argument;
  *   -ENOMEM: Not enough space/cannot allocate memory;
- *   -EEXIST: Resource with the same name already exists;
+ *   -EEXIST: Pipeline with this name already exists;
  *   -ENODEV: Extern object or table creation error.
  */
 __rte_experimental
 int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec,
-				 uint32_t *err_line,
-				 const char **err_msg);
+rte_swx_pipeline_build_from_lib(struct rte_swx_pipeline **p,
+				const char *name,
+				const char *lib_file_name,
+				FILE *iospec_file,
+				int numa_node);
 
 /**
  * Pipeline run
diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index f34803793d..3c16daf7de 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -3522,57 +3522,6 @@ pipeline_spec_configure(struct rte_swx_pipeline *p,
 	return 0;
 }
 
-int
-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,
-				 FILE *spec_file,
-				 uint32_t *err_line,
-				 const char **err_msg)
-{
-	struct pipeline_spec *s = NULL;
-	int status = 0;
-
-	/* Check the input arguments. */
-	if (!p || !spec_file) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Invalid input argument.";
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Spec file parse. */
-	s = pipeline_spec_parse(spec_file, err_line, err_msg);
-	if (!s) {
-		status = -EINVAL;
-		goto error;
-	}
-
-	/* Pipeline configure. */
-	status = pipeline_spec_configure(p, s, err_msg);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		goto error;
-	}
-
-	/* Pipeline build. */
-	status = rte_swx_pipeline_build(p);
-	if (status) {
-		if (err_line)
-			*err_line = 0;
-		if (err_msg)
-			*err_msg = "Pipeline build error.";
-		goto error;
-	}
-
-	return 0;
-
-error:
-	pipeline_spec_free(s);
-	return status;
-}
-
 static void
 port_in_params_free(void *params, const char *port_type)
 {
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 8d95005a5b..16806e6802 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -82,7 +82,6 @@ EXPERIMENTAL {
 	rte_swx_ctl_table_ops_get;
 	rte_swx_pipeline_action_config;
 	rte_swx_pipeline_build;
-	rte_swx_pipeline_build_from_spec;
 	rte_swx_pipeline_config;
 	rte_swx_pipeline_extern_func_register;
 	rte_swx_pipeline_extern_object_config;
@@ -148,6 +147,7 @@ EXPERIMENTAL {
 
 	#added in 22.11
 	rte_swx_ctl_pipeline_find;
+	rte_swx_pipeline_build_from_lib;
 	rte_swx_pipeline_codegen;
 	rte_swx_pipeline_find;
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 09/17] examples/pipeline: add CLI command for pipeline code generation
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (7 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
                     ` (8 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the pipeline code generation operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 61 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index f0285675b3..2b38977be1 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -983,6 +983,53 @@ cmd_pipeline_port_out(char **tokens,
 	}
 }
 
+static const char cmd_pipeline_codegen_help[] =
+"pipeline codegen <spec_file> <code_file>\n";
+
+static void
+cmd_pipeline_codegen(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	FILE *spec_file = NULL;
+	FILE *code_file = NULL;
+	uint32_t err_line;
+	const char *err_msg;
+	int status;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	spec_file = fopen(tokens[2], "r");
+	if (!spec_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[2]);
+		return;
+	}
+
+	code_file = fopen(tokens[3], "w");
+	if (!code_file) {
+		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
+		return;
+	}
+
+	status = rte_swx_pipeline_codegen(spec_file,
+					  code_file,
+					  &err_line,
+					  &err_msg);
+
+	fclose(spec_file);
+	fclose(code_file);
+
+	if (status) {
+		snprintf(out, out_size, "Error %d at line %u: %s\n.",
+			status, err_line, err_msg);
+		return;
+	}
+}
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
@@ -3009,6 +3056,7 @@ cmd_help(char **tokens,
 			"\tpipeline create\n"
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
+			"\tpipeline codegen\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3078,6 +3126,12 @@ cmd_help(char **tokens,
 		}
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3356,6 +3410,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "codegen") == 0)) {
+			cmd_pipeline_codegen(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 10/17] examples/pipeline: add CLI command for shared library build
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (8 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
                     ` (7 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Add CLI command for the shared object library build operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 157 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 153 insertions(+), 4 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 2b38977be1..28cf8d4178 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -6,6 +6,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <rte_common.h>
 #include <rte_ethdev.h>
@@ -25,6 +26,10 @@
 #define CMD_MAX_TOKENS     256
 #endif
 
+#ifndef MAX_LINE_SIZE
+#define MAX_LINE_SIZE 2048
+#endif
+
 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
@@ -1030,6 +1035,140 @@ cmd_pipeline_codegen(char **tokens,
 		return;
 	}
 }
+
+static const char cmd_pipeline_libbuild_help[] =
+"pipeline libbuild <code_file> <lib_file>\n";
+
+static void
+cmd_pipeline_libbuild(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	void *obj __rte_unused)
+{
+	char *code_file, *lib_file, *obj_file = NULL, *log_file = NULL;
+	char *install_dir, *cwd = NULL, *buffer = NULL;
+	size_t length;
+	int status = 0;
+
+	if (n_tokens != 4) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		goto free;
+	}
+
+	install_dir = getenv("RTE_INSTALL_DIR");
+	if (!install_dir) {
+		cwd = malloc(MAX_LINE_SIZE);
+		if (!cwd) {
+			snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+			goto free;
+		}
+
+		install_dir = getcwd(cwd, MAX_LINE_SIZE);
+		if (!install_dir) {
+			snprintf(out, out_size, "Error: Path too long.\n");
+			goto free;
+		}
+	}
+
+	snprintf(out, out_size, "Using DPDK source code from \"%s\".\n", install_dir);
+	out_size -= strlen(out);
+	out += strlen(out);
+
+	code_file = tokens[2];
+	length = strnlen(code_file, MAX_LINE_SIZE);
+	if ((length < 3) ||
+	    (code_file[length - 2] != '.') ||
+	    (code_file[length - 1] != 'c')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "code_file");
+		goto free;
+	}
+
+	lib_file = tokens[3];
+	length = strnlen(lib_file, MAX_LINE_SIZE);
+	if ((length < 4) ||
+	    (lib_file[length - 3] != '.') ||
+	    (lib_file[length - 2] != 's') ||
+	    (lib_file[length - 1] != 'o')) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "lib_file");
+		goto free;
+	}
+
+	obj_file = malloc(length);
+	log_file = malloc(length + 2);
+	if (!obj_file || !log_file) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		goto free;
+	}
+
+	memcpy(obj_file, lib_file, length - 2);
+	obj_file[length - 2] = 'o';
+	obj_file[length - 1] = 0;
+
+	memcpy(log_file, lib_file, length - 2);
+	log_file[length - 2] = 'l';
+	log_file[length - 1] = 'o';
+	log_file[length] = 'g';
+	log_file[length + 1] = 0;
+
+	buffer = malloc(MAX_LINE_SIZE);
+	if (!buffer) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		return;
+	}
+
+	snprintf(buffer,
+		 MAX_LINE_SIZE,
+		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s %s "
+		 "-I %s/lib/pipeline "
+		 "-I %s/lib/eal/include "
+		 "-I %s/lib/eal/x86/include "
+		 "-I %s/lib/eal/include/generic "
+		 "-I %s/lib/meter "
+		 "-I %s/lib/port "
+		 "-I %s/lib/table "
+		 "-I %s/lib/pipeline "
+		 "-I %s/config "
+		 "-I %s/build "
+		 "-I %s/lib/eal/linux/include "
+		 ">%s 2>&1 "
+		 "&& "
+		 "gcc -shared %s -o %s "
+		 ">>%s 2>&1",
+		 obj_file,
+		 code_file,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 install_dir,
+		 log_file,
+		 obj_file,
+		 lib_file,
+		 log_file);
+
+	status = system(buffer);
+	if (status) {
+		snprintf(out,
+			 out_size,
+			 "Library build failed, see file \"%s\" for details.\n",
+			 log_file);
+		goto free;
+	}
+
+free:
+	free(cwd);
+	free(obj_file);
+	free(log_file);
+	free(buffer);
+}
+
 static const char cmd_pipeline_build_help[] =
 "pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>\n";
 
@@ -1127,10 +1266,6 @@ table_entry_free(struct rte_swx_table_entry *entry)
 	free(entry);
 }
 
-#ifndef MAX_LINE_SIZE
-#define MAX_LINE_SIZE 2048
-#endif
-
 static int
 pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p,
 			   const char *table_name,
@@ -3057,6 +3192,7 @@ cmd_help(char **tokens,
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
+			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
 			"\tpipeline table add\n"
 			"\tpipeline table delete\n"
@@ -3132,6 +3268,12 @@ cmd_help(char **tokens,
 		return;
 	}
 
+	if ((strcmp(tokens[0], "pipeline") == 0) &&
+		(n_tokens == 2) && (strcmp(tokens[1], "libbuild") == 0)) {
+		snprintf(out, out_size, "\n%s\n", cmd_pipeline_libbuild_help);
+		return;
+	}
+
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "build") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_build_help);
@@ -3417,6 +3559,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "libbuild") == 0)) {
+			cmd_pipeline_libbuild(tokens, n_tokens, out, out_size,
+				obj);
+			return;
+		}
+
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[2], "build") == 0)) {
 			cmd_pipeline_build(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 11/17] examples/pipeline: remove the obsolete pipeline create CLI command
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (9 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
                     ` (6 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline configuration is now done through the I/O specification
file, hence this CLI command is no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 47 -----------------------------------------
 1 file changed, 47 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 28cf8d4178..7b725a9c27 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -523,39 +523,6 @@ cmd_tap(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_create_help[] =
-"pipeline <pipeline_name> create <numa_node>\n";
-
-static void
-cmd_pipeline_create(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	char *name;
-	uint32_t numa_node;
-
-	if (n_tokens != 4) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	name = tokens[1];
-
-	if (parser_read_uint32(&numa_node, tokens[3]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "numa_node");
-		return;
-	}
-
-	p = pipeline_create(obj, name, (int)numa_node);
-	if (!p) {
-		snprintf(out, out_size, "pipeline create error.");
-		return;
-	}
-}
-
 static const char cmd_pipeline_port_in_help[] =
 "pipeline <pipeline_name> port in <port_id>\n"
 "   link <link_name> rxq <queue_id> bsz <burst_size>\n"
@@ -3188,7 +3155,6 @@ cmd_help(char **tokens,
 			"\tmempool\n"
 			"\tlink\n"
 			"\ttap\n"
-			"\tpipeline create\n"
 			"\tpipeline port in\n"
 			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
@@ -3241,12 +3207,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if ((strcmp(tokens[0], "pipeline") == 0) &&
-		(n_tokens == 2) && (strcmp(tokens[1], "create") == 0)) {
-		snprintf(out, out_size, "\n%s\n", cmd_pipeline_create_help);
-		return;
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
 		if (strcmp(tokens[2], "in") == 0) {
@@ -3529,13 +3489,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 	}
 
 	if (strcmp(tokens[0], "pipeline") == 0) {
-		if ((n_tokens >= 3) &&
-			(strcmp(tokens[2], "create") == 0)) {
-			cmd_pipeline_create(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
 		if ((n_tokens >= 4) &&
 			(strcmp(tokens[2], "port") == 0) &&
 			(strcmp(tokens[3], "in") == 0)) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 12/17] examples/pipeline: remove the obsolete port configuration CLI commands
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (10 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
                     ` (5 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline I/O ports configuration is now done through the I/O
specification file, hence these CLI commands are no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 465 ----------------------------------------
 1 file changed, 465 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index 7b725a9c27..b26e73c706 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -523,438 +523,6 @@ cmd_tap(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_port_in_help[] =
-"pipeline <pipeline_name> port in <port_id>\n"
-"   link <link_name> rxq <queue_id> bsz <burst_size>\n"
-"   ring <ring_name> bsz <burst_size>\n"
-"   | source <mempool_name> <file_name> loop <n_loops>\n"
-"   | tap <tap_name> mempool <mempool_name> mtu <mtu> bsz <burst_size>\n";
-
-static void
-cmd_pipeline_port_in(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	int status;
-	uint32_t port_id = 0, t0;
-
-	if (n_tokens < 6) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[2], "port") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
-		return;
-	}
-
-	if (strcmp(tokens[3], "in") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
-		return;
-	}
-
-	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-		return;
-	}
-
-	t0 = 5;
-
-	if (strcmp(tokens[t0], "link") == 0) {
-		struct rte_swx_port_ethdev_reader_params params;
-		struct link *link;
-
-		if (n_tokens < t0 + 6) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in link");
-			return;
-		}
-
-		link = link_find(obj, tokens[t0 + 1]);
-		if (!link) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"link_name");
-			return;
-		}
-		params.dev_name = link->dev_name;
-
-		if (strcmp(tokens[t0 + 2], "rxq") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
-			return;
-		}
-
-		if (parser_read_uint16(&params.queue_id, tokens[t0 + 3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"queue_id");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 4], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 5])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 6;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"ethdev",
-			&params);
-	} else if (strcmp(tokens[t0], "ring") == 0) {
-		struct rte_swx_port_ring_reader_params params;
-		struct ring *ring;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in ring");
-			return;
-		}
-
-		ring = ring_find(obj, tokens[t0 + 1]);
-		if (!ring) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"ring_name");
-			return;
-		}
-		params.name = ring->name;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"ring",
-			&params);
-	} else if (strcmp(tokens[t0], "source") == 0) {
-		struct rte_swx_port_source_params params;
-		struct mempool *mp;
-
-		if (n_tokens < t0 + 5) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in source");
-			return;
-		}
-
-		mp = mempool_find(obj, tokens[t0 + 1]);
-		if (!mp) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"mempool_name");
-			return;
-		}
-		params.pool = mp->m;
-
-		params.file_name = tokens[t0 + 2];
-
-		if (strcmp(tokens[t0 + 3], "loop") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "loop");
-			return;
-		}
-
-		if (parser_read_uint64(&params.n_loops, tokens[t0 + 4])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"n_loops");
-			return;
-		}
-
-		t0 += 5;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"source",
-			&params);
-	} else if (strcmp(tokens[t0], "tap") == 0) {
-		struct rte_swx_port_fd_reader_params params;
-		struct tap *tap;
-		struct mempool *mp;
-
-		if (n_tokens < t0 + 8) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port in tap");
-			return;
-		}
-
-		tap = tap_find(obj, tokens[t0 + 1]);
-		if (!tap) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"tap_name");
-			return;
-		}
-		params.fd = tap->fd;
-
-		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
-				"mempool");
-			return;
-		}
-
-		mp = mempool_find(obj, tokens[t0 + 3]);
-		if (!mp) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"mempool_name");
-			return;
-		}
-		params.mempool = mp->m;
-
-		if (strcmp(tokens[t0 + 4], "mtu") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
-				"mtu");
-			return;
-		}
-
-		if (parser_read_uint32(&params.mtu, tokens[t0 + 5]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 6], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 7])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 8;
-
-		status = rte_swx_pipeline_port_in_config(p->p,
-			port_id,
-			"fd",
-			&params);
-
-	} else {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (status) {
-		snprintf(out, out_size, "port in error.");
-		return;
-	}
-
-	if (n_tokens != t0) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-}
-
-static const char cmd_pipeline_port_out_help[] =
-"pipeline <pipeline_name> port out <port_id>\n"
-"   link <link_name> txq <txq_id> bsz <burst_size>\n"
-"   ring <ring_name> bsz <burst_size>\n"
-"   | sink <file_name> | none\n"
-"   | tap <tap_name> bsz <burst_size>\n";
-
-static void
-cmd_pipeline_port_out(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct pipeline *p;
-	int status;
-	uint32_t port_id = 0, t0;
-
-	if (n_tokens < 6) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || p->ctl) {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[2], "port") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
-		return;
-	}
-
-	if (strcmp(tokens[3], "out") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
-		return;
-	}
-
-	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-		return;
-	}
-
-	t0 = 5;
-
-	if (strcmp(tokens[t0], "link") == 0) {
-		struct rte_swx_port_ethdev_writer_params params;
-		struct link *link;
-
-		if (n_tokens < t0 + 6) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out link");
-			return;
-		}
-
-		link = link_find(obj, tokens[t0 + 1]);
-		if (!link) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"link_name");
-			return;
-		}
-		params.dev_name = link->dev_name;
-
-		if (strcmp(tokens[t0 + 2], "txq") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
-			return;
-		}
-
-		if (parser_read_uint16(&params.queue_id, tokens[t0 + 3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"queue_id");
-			return;
-		}
-
-		if (strcmp(tokens[t0 + 4], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 5])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 6;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"ethdev",
-			&params);
-	} else if (strcmp(tokens[t0], "ring") == 0) {
-		struct rte_swx_port_ring_writer_params params;
-		struct ring *ring;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out link");
-			return;
-		}
-
-		ring = ring_find(obj, tokens[t0 + 1]);
-		if (!ring) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"ring_name");
-			return;
-		}
-		params.name = ring->name;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"ring",
-			&params);
-	} else if (strcmp(tokens[t0], "sink") == 0) {
-		struct rte_swx_port_sink_params params;
-
-		params.file_name = strcmp(tokens[t0 + 1], "none") ?
-			tokens[t0 + 1] : NULL;
-
-		t0 += 2;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"sink",
-			&params);
-	} else if (strcmp(tokens[t0], "tap") == 0) {
-		struct rte_swx_port_fd_writer_params params;
-		struct tap *tap;
-
-		if (n_tokens < t0 + 4) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH,
-				"pipeline port out tap");
-			return;
-		}
-
-		tap = tap_find(obj, tokens[t0 + 1]);
-		if (!tap) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"tap_name");
-			return;
-		}
-		params.fd = tap->fd;
-
-		if (strcmp(tokens[t0 + 2], "bsz") != 0) {
-			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
-			return;
-		}
-
-		if (parser_read_uint32(&params.burst_size, tokens[t0 + 3])) {
-			snprintf(out, out_size, MSG_ARG_INVALID,
-				"burst_size");
-			return;
-		}
-
-		t0 += 4;
-
-		status = rte_swx_pipeline_port_out_config(p->p,
-			port_id,
-			"fd",
-			&params);
-	} else {
-		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
-		return;
-	}
-
-	if (status) {
-		snprintf(out, out_size, "port out error.");
-		return;
-	}
-
-	if (n_tokens != t0) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-}
-
 static const char cmd_pipeline_codegen_help[] =
 "pipeline codegen <spec_file> <code_file>\n";
 
@@ -3155,8 +2723,6 @@ cmd_help(char **tokens,
 			"\tmempool\n"
 			"\tlink\n"
 			"\ttap\n"
-			"\tpipeline port in\n"
-			"\tpipeline port out\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
@@ -3207,21 +2773,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if ((strcmp(tokens[0], "pipeline") == 0) &&
-		(n_tokens == 3) && (strcmp(tokens[1], "port") == 0)) {
-		if (strcmp(tokens[2], "in") == 0) {
-			snprintf(out, out_size, "\n%s\n",
-				cmd_pipeline_port_in_help);
-			return;
-		}
-
-		if (strcmp(tokens[2], "out") == 0) {
-			snprintf(out, out_size, "\n%s\n",
-				cmd_pipeline_port_out_help);
-			return;
-		}
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
@@ -3489,22 +3040,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 	}
 
 	if (strcmp(tokens[0], "pipeline") == 0) {
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "port") == 0) &&
-			(strcmp(tokens[3], "in") == 0)) {
-			cmd_pipeline_port_in(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "port") == 0) &&
-			(strcmp(tokens[3], "out") == 0)) {
-			cmd_pipeline_port_out(tokens, n_tokens, out, out_size,
-				obj);
-			return;
-		}
-
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[1], "codegen") == 0)) {
 			cmd_pipeline_codegen(tokens, n_tokens, out, out_size,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (11 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
                     ` (4 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

The pipeline mirroring configuration is done through the I/O
specification file, so this CLI command is no longer needed.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 76 -----------------------------------------
 1 file changed, 76 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index b26e73c706..fa828c008b 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -2457,68 +2457,6 @@ cmd_pipeline_stats(char **tokens,
 	}
 }
 
-static const char cmd_pipeline_mirror_help[] =
-"pipeline <pipeline_name> mirror slots <n_slots> sessions <n_sessions>\n";
-
-static void
-cmd_pipeline_mirror(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct rte_swx_pipeline_mirroring_params params;
-	struct pipeline *p;
-	int status;
-
-	if (n_tokens != 7) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-
-	if (strcmp(tokens[0], "pipeline")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
-		return;
-	}
-
-	p = pipeline_find(obj, tokens[1]);
-	if (!p) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
-		return;
-	}
-
-	if (strcmp(tokens[2], "mirror")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror");
-		return;
-	}
-
-	if (strcmp(tokens[3], "slots")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "slots");
-		return;
-	}
-
-	if (parser_read_uint32(&params.n_slots, tokens[4])) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "n_slots");
-		return;
-	}
-
-	if (strcmp(tokens[5], "sessions")) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "sessions");
-		return;
-	}
-
-	if (parser_read_uint32(&params.n_sessions, tokens[6])) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "n_sessions");
-		return;
-	}
-
-	status = rte_swx_pipeline_mirroring_config(p->p, &params);
-	if (status) {
-		snprintf(out, out_size, "Command failed!\n");
-		return;
-	}
-}
-
 static const char cmd_pipeline_mirror_session_help[] =
 "pipeline <pipeline_name> mirror session <session_id> port <port_id> clone fast | slow "
 "truncate <truncation_length>\n";
@@ -2746,7 +2684,6 @@ cmd_help(char **tokens,
 			"\tpipeline meter set\n"
 			"\tpipeline meter stats\n"
 			"\tpipeline stats\n"
-			"\tpipeline mirror\n"
 			"\tpipeline mirror session\n"
 			"\tthread pipeline enable\n"
 			"\tthread pipeline disable\n\n");
@@ -2958,12 +2895,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (!strcmp(tokens[0], "pipeline") &&
-		(n_tokens == 2) && !strcmp(tokens[1], "mirror")) {
-		snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_help);
-		return;
-	}
-
 	if (!strcmp(tokens[0], "pipeline") &&
 		(n_tokens == 3) && !strcmp(tokens[1], "mirror")
 		&& !strcmp(tokens[2], "session")) {
@@ -3217,13 +3148,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 			return;
 		}
 
-		if ((n_tokens >= 4) &&
-			(strcmp(tokens[2], "mirror") == 0) &&
-			(strcmp(tokens[3], "slots") == 0)) {
-			cmd_pipeline_mirror(tokens, n_tokens, out, out_size, obj);
-			return;
-		}
-
 		if ((n_tokens >= 4) &&
 			(strcmp(tokens[2], "mirror") == 0) &&
 			(strcmp(tokens[3], "session") == 0)) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 14/17] examples/pipeline: use the pipeline name query API
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (12 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
                     ` (3 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Convert the CLI commands to use the pipeline name query API and remove
the linked list of pipeline objects previously maintained by the
application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c    | 268 ++++++++++++++++++++-----------------
 examples/pipeline/obj.c    |  67 ----------
 examples/pipeline/obj.h    |  24 ----
 examples/pipeline/thread.c |  65 ++++-----
 examples/pipeline/thread.h |   9 +-
 5 files changed, 175 insertions(+), 258 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index fa828c008b..f48ff326be 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -858,9 +858,9 @@ cmd_pipeline_table_add(char **tokens,
 		       uint32_t n_tokens,
 		       char *out,
 		       size_t out_size,
-		       void *obj)
+		       void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -872,8 +872,8 @@ cmd_pipeline_table_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -887,7 +887,7 @@ cmd_pipeline_table_add(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_entries_add(p->ctl,
+	status = pipeline_table_entries_add(ctl,
 					    table_name,
 					    file,
 					    &file_line_number);
@@ -956,9 +956,9 @@ cmd_pipeline_table_delete(char **tokens,
 			  uint32_t n_tokens,
 			  char *out,
 			  size_t out_size,
-			  void *obj)
+			  void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -970,8 +970,8 @@ cmd_pipeline_table_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -985,7 +985,7 @@ cmd_pipeline_table_delete(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_entries_delete(p->ctl,
+	status = pipeline_table_entries_delete(ctl,
 					       table_name,
 					       file,
 					       &file_line_number);
@@ -1054,9 +1054,9 @@ cmd_pipeline_table_default(char **tokens,
 			   uint32_t n_tokens,
 			   char *out,
 			   size_t out_size,
-			   void *obj)
+			   void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1068,8 +1068,8 @@ cmd_pipeline_table_default(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1083,7 +1083,7 @@ cmd_pipeline_table_default(char **tokens,
 		return;
 	}
 
-	status = pipeline_table_default_entry_add(p->ctl,
+	status = pipeline_table_default_entry_add(ctl,
 						  table_name,
 						  file,
 						  &file_line_number);
@@ -1103,9 +1103,9 @@ cmd_pipeline_table_show(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *table_name;
 	FILE *file = NULL;
 	int status;
@@ -1116,8 +1116,8 @@ cmd_pipeline_table_show(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1129,7 +1129,7 @@ cmd_pipeline_table_show(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_table_fprintf(file, p->ctl, table_name);
+	status = rte_swx_ctl_pipeline_table_fprintf(file, ctl, table_name);
 	if (status)
 		snprintf(out, out_size, MSG_ARG_INVALID, "table_name");
 
@@ -1145,9 +1145,9 @@ cmd_pipeline_selector_group_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	uint32_t group_id;
 	int status;
@@ -1158,8 +1158,8 @@ cmd_pipeline_selector_group_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1177,7 +1177,7 @@ cmd_pipeline_selector_group_add(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_group_add(p->ctl,
+	status = rte_swx_ctl_pipeline_selector_group_add(ctl,
 		selector_name,
 		&group_id);
 	if (status)
@@ -1194,9 +1194,9 @@ cmd_pipeline_selector_group_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	uint32_t group_id;
 	int status;
@@ -1207,8 +1207,8 @@ cmd_pipeline_selector_group_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1231,7 +1231,7 @@ cmd_pipeline_selector_group_delete(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_group_delete(p->ctl,
+	status = rte_swx_ctl_pipeline_selector_group_delete(ctl,
 		selector_name,
 		group_id);
 	if (status)
@@ -1402,9 +1402,9 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1416,8 +1416,8 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1443,7 +1443,7 @@ cmd_pipeline_selector_group_member_add(char **tokens,
 		return;
 	}
 
-	status = pipeline_selector_group_members_add(p->ctl,
+	status = pipeline_selector_group_members_add(ctl,
 					    selector_name,
 					    file,
 					    &file_line_number);
@@ -1512,9 +1512,9 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1526,8 +1526,8 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1553,7 +1553,7 @@ cmd_pipeline_selector_group_member_delete(char **tokens,
 		return;
 	}
 
-	status = pipeline_selector_group_members_delete(p->ctl,
+	status = pipeline_selector_group_members_delete(ctl,
 					    selector_name,
 					    file,
 					    &file_line_number);
@@ -1573,9 +1573,9 @@ cmd_pipeline_selector_show(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *selector_name;
 	FILE *file = NULL;
 	int status;
@@ -1586,8 +1586,8 @@ cmd_pipeline_selector_show(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1600,7 +1600,7 @@ cmd_pipeline_selector_show(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_selector_fprintf(file, p->ctl, selector_name);
+	status = rte_swx_ctl_pipeline_selector_fprintf(file, ctl, selector_name);
 	if (status)
 		snprintf(out, out_size, MSG_ARG_INVALID, "selector_name");
 
@@ -1665,9 +1665,9 @@ cmd_pipeline_learner_default(char **tokens,
 			     uint32_t n_tokens,
 			     char *out,
 			     size_t out_size,
-			     void *obj)
+			     void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name, *learner_name, *file_name;
 	FILE *file = NULL;
 	uint32_t file_line_number = 0;
@@ -1679,8 +1679,8 @@ cmd_pipeline_learner_default(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1694,7 +1694,7 @@ cmd_pipeline_learner_default(char **tokens,
 		return;
 	}
 
-	status = pipeline_learner_default_entry_add(p->ctl,
+	status = pipeline_learner_default_entry_add(ctl,
 						    learner_name,
 						    file,
 						    &file_line_number);
@@ -1714,9 +1714,9 @@ cmd_pipeline_commit(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name;
 	int status;
 
@@ -1726,13 +1726,13 @@ cmd_pipeline_commit(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_commit(p->ctl, 1);
+	status = rte_swx_ctl_pipeline_commit(ctl, 1);
 	if (status)
 		snprintf(out, out_size, "Commit failed. "
 			"Use \"commit\" to retry or \"abort\" to discard the pending work.\n");
@@ -1746,9 +1746,9 @@ cmd_pipeline_abort(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 	char *pipeline_name;
 
 	if (n_tokens != 3) {
@@ -1757,13 +1757,13 @@ cmd_pipeline_abort(char **tokens,
 	}
 
 	pipeline_name = tokens[1];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	ctl = rte_swx_ctl_pipeline_find(pipeline_name);
+	if (!ctl) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
 
-	rte_swx_ctl_pipeline_abort(p->ctl);
+	rte_swx_ctl_pipeline_abort(ctl);
 }
 
 static const char cmd_pipeline_regrd_help[] =
@@ -1774,9 +1774,9 @@ cmd_pipeline_regrd(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint64_t value;
 	uint32_t idx;
@@ -1787,8 +1787,8 @@ cmd_pipeline_regrd(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1805,7 +1805,7 @@ cmd_pipeline_regrd(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value);
+	status = rte_swx_ctl_pipeline_regarray_read(p, name, idx, &value);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1822,9 +1822,9 @@ cmd_pipeline_regwr(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint64_t value;
 	uint32_t idx;
@@ -1835,8 +1835,8 @@ cmd_pipeline_regwr(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1858,7 +1858,7 @@ cmd_pipeline_regwr(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value);
+	status = rte_swx_ctl_pipeline_regarray_write(p, name, idx, value);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1874,10 +1874,10 @@ cmd_pipeline_meter_profile_add(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_meter_trtcm_params params;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *profile_name;
 	int status;
 
@@ -1886,8 +1886,8 @@ cmd_pipeline_meter_profile_add(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1949,7 +1949,7 @@ cmd_pipeline_meter_profile_add(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_meter_profile_add(p->p, profile_name, &params);
+	status = rte_swx_ctl_meter_profile_add(p, profile_name, &params);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -1964,9 +1964,9 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *profile_name;
 	int status;
 
@@ -1975,8 +1975,8 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -1998,7 +1998,7 @@ cmd_pipeline_meter_profile_delete(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_meter_profile_delete(p->p, profile_name);
+	status = rte_swx_ctl_meter_profile_delete(p, profile_name);
 	if (status) {
 		snprintf(out, out_size, "Command failed.\n");
 		return;
@@ -2014,9 +2014,9 @@ cmd_pipeline_meter_reset(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2025,8 +2025,8 @@ cmd_pipeline_meter_reset(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2066,7 +2066,7 @@ cmd_pipeline_meter_reset(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_reset(p->p, name, idx0);
+		status = rte_swx_ctl_meter_reset(p, name, idx0);
 		if (status) {
 			snprintf(out, out_size, "Command failed for index %u.\n", idx0);
 			return;
@@ -2083,9 +2083,9 @@ cmd_pipeline_meter_set(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name, *profile_name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2094,8 +2094,8 @@ cmd_pipeline_meter_set(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2142,7 +2142,7 @@ cmd_pipeline_meter_set(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name);
+		status = rte_swx_ctl_meter_set(p, name, idx0, profile_name);
 		if (status) {
 			snprintf(out, out_size, "Command failed for index %u.\n", idx0);
 			return;
@@ -2159,10 +2159,10 @@ cmd_pipeline_meter_stats(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_ctl_meter_stats stats;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	const char *name;
 	uint32_t idx0 = 0, idx1 = 0;
 
@@ -2171,8 +2171,8 @@ cmd_pipeline_meter_stats(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2235,7 +2235,7 @@ cmd_pipeline_meter_stats(char **tokens,
 	for ( ; idx0 <= idx1; idx0++) {
 		int status;
 
-		status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats);
+		status = rte_swx_ctl_meter_stats_read(p, name, idx0, &stats);
 		if (status) {
 			snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0);
 			out_size -= strlen(out);
@@ -2265,10 +2265,10 @@ cmd_pipeline_stats(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_ctl_pipeline_info info;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	uint32_t i;
 	int status;
 
@@ -2277,8 +2277,8 @@ cmd_pipeline_stats(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2288,7 +2288,7 @@ cmd_pipeline_stats(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_info_get(p->p, &info);
+	status = rte_swx_ctl_pipeline_info_get(p, &info);
 	if (status) {
 		snprintf(out, out_size, "Pipeline info get error.");
 		return;
@@ -2301,7 +2301,7 @@ cmd_pipeline_stats(char **tokens,
 	for (i = 0; i < info.n_ports_in; i++) {
 		struct rte_swx_port_in_stats stats;
 
-		rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats);
+		rte_swx_ctl_pipeline_port_in_stats_read(p, i, &stats);
 
 		snprintf(out, out_size, "\tPort %u:"
 			" packets %" PRIu64
@@ -2319,7 +2319,7 @@ cmd_pipeline_stats(char **tokens,
 	for (i = 0; i < info.n_ports_out; i++) {
 		struct rte_swx_port_out_stats stats;
 
-		rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats);
+		rte_swx_ctl_pipeline_port_out_stats_read(p, i, &stats);
 
 		if (i != info.n_ports_out - 1)
 			snprintf(out, out_size, "\tPort %u:", i);
@@ -2358,13 +2358,13 @@ cmd_pipeline_stats(char **tokens,
 		};
 		uint32_t j;
 
-		status = rte_swx_ctl_table_info_get(p->p, i, &table_info);
+		status = rte_swx_ctl_table_info_get(p, i, &table_info);
 		if (status) {
 			snprintf(out, out_size, "Table info get error.");
 			return;
 		}
 
-		status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats);
+		status = rte_swx_ctl_pipeline_table_stats_read(p, table_info.name, &stats);
 		if (status) {
 			snprintf(out, out_size, "Table stats read error.");
 			return;
@@ -2382,7 +2382,7 @@ cmd_pipeline_stats(char **tokens,
 		for (j = 0; j < info.n_actions; j++) {
 			struct rte_swx_ctl_action_info action_info;
 
-			status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
+			status = rte_swx_ctl_action_info_get(p, j, &action_info);
 			if (status) {
 				snprintf(out, out_size, "Action info get error.");
 				return;
@@ -2410,13 +2410,13 @@ cmd_pipeline_stats(char **tokens,
 		};
 		uint32_t j;
 
-		status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info);
+		status = rte_swx_ctl_learner_info_get(p, i, &learner_info);
 		if (status) {
 			snprintf(out, out_size, "Learner table info get error.");
 			return;
 		}
 
-		status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats);
+		status = rte_swx_ctl_pipeline_learner_stats_read(p, learner_info.name, &stats);
 		if (status) {
 			snprintf(out, out_size, "Learner table stats read error.");
 			return;
@@ -2442,7 +2442,7 @@ cmd_pipeline_stats(char **tokens,
 		for (j = 0; j < info.n_actions; j++) {
 			struct rte_swx_ctl_action_info action_info;
 
-			status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
+			status = rte_swx_ctl_action_info_get(p, j, &action_info);
 			if (status) {
 				snprintf(out, out_size, "Action info get error.");
 				return;
@@ -2466,10 +2466,10 @@ cmd_pipeline_mirror_session(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	struct rte_swx_pipeline_mirroring_session_params params;
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	uint32_t session_id = 0;
 	int status;
 
@@ -2483,8 +2483,8 @@ cmd_pipeline_mirror_session(char **tokens,
 		return;
 	}
 
-	p = pipeline_find(obj, tokens[1]);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(tokens[1]);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2538,7 +2538,7 @@ cmd_pipeline_mirror_session(char **tokens,
 		return;
 	}
 
-	status = rte_swx_ctl_pipeline_mirroring_session_set(p->p, session_id, &params);
+	status = rte_swx_ctl_pipeline_mirroring_session_set(p, session_id, &params);
 	if (status) {
 		snprintf(out, out_size, "Command failed!\n");
 		return;
@@ -2546,21 +2546,25 @@ cmd_pipeline_mirror_session(char **tokens,
 }
 
 static const char cmd_thread_pipeline_enable_help[] =
-"thread <thread_id> pipeline <pipeline_name> enable\n";
+"thread <thread_id> pipeline <pipeline_name> enable [ period <timer_period_ms> ]\n";
+
+#ifndef TIMER_PERIOD_MS_DEFAULT
+#define TIMER_PERIOD_MS_DEFAULT 10
+#endif
 
 static void
 cmd_thread_pipeline_enable(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
 	char *pipeline_name;
-	struct pipeline *p;
-	uint32_t thread_id;
+	struct rte_swx_pipeline *p;
+	uint32_t thread_id, timer_period_ms = TIMER_PERIOD_MS_DEFAULT;
 	int status;
 
-	if (n_tokens != 5) {
+	if ((n_tokens != 5) && (n_tokens != 7)) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
@@ -2576,8 +2580,8 @@ cmd_thread_pipeline_enable(char **tokens,
 	}
 
 	pipeline_name = tokens[3];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(pipeline_name);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2587,7 +2591,19 @@ cmd_thread_pipeline_enable(char **tokens,
 		return;
 	}
 
-	status = thread_pipeline_enable(thread_id, obj, pipeline_name);
+	if (n_tokens == 7) {
+		if (strcmp(tokens[5], "period") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
+			return;
+		}
+
+		if (parser_read_uint32(&timer_period_ms, tokens[6]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
+			return;
+		}
+	}
+
+	status = thread_pipeline_enable(thread_id, p, timer_period_ms);
 	if (status) {
 		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
 		return;
@@ -2602,9 +2618,9 @@ cmd_thread_pipeline_disable(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
-	void *obj)
+	void *obj __rte_unused)
 {
-	struct pipeline *p;
+	struct rte_swx_pipeline *p;
 	char *pipeline_name;
 	uint32_t thread_id;
 	int status;
@@ -2625,8 +2641,8 @@ cmd_thread_pipeline_disable(char **tokens,
 	}
 
 	pipeline_name = tokens[3];
-	p = pipeline_find(obj, pipeline_name);
-	if (!p || !p->ctl) {
+	p = rte_swx_pipeline_find(pipeline_name);
+	if (!p) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
 		return;
 	}
@@ -2636,7 +2652,7 @@ cmd_thread_pipeline_disable(char **tokens,
 		return;
 	}
 
-	status = thread_pipeline_disable(thread_id, obj, pipeline_name);
+	status = thread_pipeline_disable(thread_id, p);
 	if (status) {
 		snprintf(out, out_size, MSG_CMD_FAIL,
 			"thread pipeline disable");
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index 967342c580..d1f519180e 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -16,7 +16,6 @@
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
 #include <rte_ethdev.h>
-#include <rte_swx_pipeline.h>
 #include <rte_swx_ctl.h>
 
 #include "obj.h"
@@ -41,11 +40,6 @@ TAILQ_HEAD(ring_list, ring);
  */
 TAILQ_HEAD(tap_list, tap);
 
-/*
- * pipeline
- */
-TAILQ_HEAD(pipeline_list, pipeline);
-
 /*
  * obj
  */
@@ -53,7 +47,6 @@ struct obj {
 	struct mempool_list mempool_list;
 	struct link_list link_list;
 	struct ring_list ring_list;
-	struct pipeline_list pipeline_list;
 	struct tap_list tap_list;
 };
 
@@ -513,65 +506,6 @@ tap_create(struct obj *obj, const char *name)
 
 #endif
 
-/*
- * pipeline
- */
-#ifndef PIPELINE_MSGQ_SIZE
-#define PIPELINE_MSGQ_SIZE                                 64
-#endif
-
-struct pipeline *
-pipeline_create(struct obj *obj, const char *name, int numa_node)
-{
-	struct pipeline *pipeline;
-	struct rte_swx_pipeline *p = NULL;
-	int status;
-
-	/* Check input params */
-	if ((name == NULL) ||
-		pipeline_find(obj, name))
-		return NULL;
-
-	/* Resource create */
-	status = rte_swx_pipeline_config(&p, name, numa_node);
-	if (status)
-		goto error;
-
-	/* Node allocation */
-	pipeline = calloc(1, sizeof(struct pipeline));
-	if (pipeline == NULL)
-		goto error;
-
-	/* Node fill in */
-	strlcpy(pipeline->name, name, sizeof(pipeline->name));
-	pipeline->p = p;
-	pipeline->timer_period_ms = 10;
-
-	/* Node add to list */
-	TAILQ_INSERT_TAIL(&obj->pipeline_list, pipeline, node);
-
-	return pipeline;
-
-error:
-	rte_swx_pipeline_free(p);
-	return NULL;
-}
-
-struct pipeline *
-pipeline_find(struct obj *obj, const char *name)
-{
-	struct pipeline *pipeline;
-
-	if (!obj || !name)
-		return NULL;
-
-	TAILQ_FOREACH(pipeline, &obj->pipeline_list, node)
-		if (strcmp(name, pipeline->name) == 0)
-			return pipeline;
-
-	return NULL;
-}
-
 /*
  * obj
  */
@@ -587,7 +521,6 @@ obj_init(void)
 	TAILQ_INIT(&obj->mempool_list);
 	TAILQ_INIT(&obj->link_list);
 	TAILQ_INIT(&obj->ring_list);
-	TAILQ_INIT(&obj->pipeline_list);
 	TAILQ_INIT(&obj->tap_list);
 
 	return obj;
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index b921610554..e63a9c0e9a 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -143,28 +143,4 @@ tap_next(struct obj *obj, struct tap *tap);
 struct tap *
 tap_create(struct obj *obj, const char *name);
 
-/*
- * pipeline
- */
-struct pipeline {
-	TAILQ_ENTRY(pipeline) node;
-	char name[NAME_SIZE];
-
-	struct rte_swx_pipeline *p;
-	struct rte_swx_ctl_pipeline *ctl;
-
-	uint32_t timer_period_ms;
-	int enabled;
-	uint32_t thread_id;
-	uint32_t cpu_id;
-};
-
-struct pipeline *
-pipeline_create(struct obj *obj,
-		const char *name,
-		int numa_node);
-
-struct pipeline *
-pipeline_find(struct obj *obj, const char *name);
-
 #endif /* _INCLUDE_OBJ_H_ */
diff --git a/examples/pipeline/thread.c b/examples/pipeline/thread.c
index 5fe7eae00e..6d15f51fb2 100644
--- a/examples/pipeline/thread.c
+++ b/examples/pipeline/thread.c
@@ -228,20 +228,33 @@ thread_msg_send_recv(uint32_t thread_id,
 	return rsp;
 }
 
+static int
+thread_is_pipeline_enabled(uint32_t thread_id, struct rte_swx_pipeline *p)
+{
+	struct thread *t = &thread[thread_id];
+	struct thread_data *td = &thread_data[thread_id];
+	uint32_t i;
+
+	if (!t->enabled)
+		return 0; /* Pipeline NOT enabled on this thread. */
+
+	for (i = 0; i < td->n_pipelines; i++)
+		if (td->p[i] == p)
+			return 1; /* Pipeline enabled on this thread. */
+
+	return 0 /* Pipeline NOT enabled on this thread. */;
+}
+
 int
-thread_pipeline_enable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name)
+thread_pipeline_enable(uint32_t thread_id, struct rte_swx_pipeline *p, uint32_t timer_period_ms)
 {
-	struct pipeline *p = pipeline_find(obj, pipeline_name);
 	struct thread *t;
 	struct thread_msg_req *req;
 	struct thread_msg_rsp *rsp;
 	int status;
 
 	/* Check input params */
-	if ((thread_id >= RTE_MAX_LCORE) ||
-		(p == NULL))
+	if ((thread_id >= RTE_MAX_LCORE) || !p || !timer_period_ms)
 		return -1;
 
 	t = &thread[thread_id];
@@ -256,19 +269,14 @@ thread_pipeline_enable(uint32_t thread_id,
 			return -1;
 
 		/* Data plane thread */
-		td->p[td->n_pipelines] = p->p;
+		td->p[td->n_pipelines] = p;
 
-		tdp->p = p->p;
-		tdp->timer_period =
-			(rte_get_tsc_hz() * p->timer_period_ms) / 1000;
+		tdp->p = p;
+		tdp->timer_period = (rte_get_tsc_hz() * timer_period_ms) / 1000;
 		tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
 
 		td->n_pipelines++;
 
-		/* Pipeline */
-		p->thread_id = thread_id;
-		p->enabled = 1;
-
 		return 0;
 	}
 
@@ -279,8 +287,8 @@ thread_pipeline_enable(uint32_t thread_id,
 
 	/* Write request */
 	req->type = THREAD_REQ_PIPELINE_ENABLE;
-	req->pipeline_enable.p = p->p;
-	req->pipeline_enable.timer_period_ms = p->timer_period_ms;
+	req->pipeline_enable.p = p;
+	req->pipeline_enable.timer_period_ms = timer_period_ms;
 
 	/* Send request and wait for response */
 	rsp = thread_msg_send_recv(thread_id, req);
@@ -295,38 +303,28 @@ thread_pipeline_enable(uint32_t thread_id,
 	if (status)
 		return status;
 
-	p->thread_id = thread_id;
-	p->enabled = 1;
-
 	return 0;
 }
 
 int
-thread_pipeline_disable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name)
+thread_pipeline_disable(uint32_t thread_id, struct rte_swx_pipeline *p)
 {
-	struct pipeline *p = pipeline_find(obj, pipeline_name);
 	struct thread *t;
 	struct thread_msg_req *req;
 	struct thread_msg_rsp *rsp;
 	int status;
 
 	/* Check input params */
-	if ((thread_id >= RTE_MAX_LCORE) ||
-		(p == NULL))
+	if ((thread_id >= RTE_MAX_LCORE) || !p)
 		return -1;
 
 	t = &thread[thread_id];
 	if (t->enabled == 0)
 		return -1;
 
-	if (p->enabled == 0)
+	if (!thread_is_pipeline_enabled(thread_id, p))
 		return 0;
 
-	if (p->thread_id != thread_id)
-		return -1;
-
 	if (!thread_is_running(thread_id)) {
 		struct thread_data *td = &thread_data[thread_id];
 		uint32_t i;
@@ -334,7 +332,7 @@ thread_pipeline_disable(uint32_t thread_id,
 		for (i = 0; i < td->n_pipelines; i++) {
 			struct pipeline_data *tdp = &td->pipeline_data[i];
 
-			if (tdp->p != p->p)
+			if (tdp->p != p)
 				continue;
 
 			/* Data plane thread */
@@ -350,9 +348,6 @@ thread_pipeline_disable(uint32_t thread_id,
 
 			td->n_pipelines--;
 
-			/* Pipeline */
-			p->enabled = 0;
-
 			break;
 		}
 
@@ -366,7 +361,7 @@ thread_pipeline_disable(uint32_t thread_id,
 
 	/* Write request */
 	req->type = THREAD_REQ_PIPELINE_DISABLE;
-	req->pipeline_disable.p = p->p;
+	req->pipeline_disable.p = p;
 
 	/* Send request and wait for response */
 	rsp = thread_msg_send_recv(thread_id, req);
@@ -381,8 +376,6 @@ thread_pipeline_disable(uint32_t thread_id,
 	if (status)
 		return status;
 
-	p->enabled = 0;
-
 	return 0;
 }
 
diff --git a/examples/pipeline/thread.h b/examples/pipeline/thread.h
index d9d8645d4c..712cb25bbb 100644
--- a/examples/pipeline/thread.h
+++ b/examples/pipeline/thread.h
@@ -7,17 +7,16 @@
 
 #include <stdint.h>
 
-#include "obj.h"
+#include <rte_swx_pipeline.h>
 
 int
 thread_pipeline_enable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name);
+		       struct rte_swx_pipeline *p,
+		       uint32_t timer_period_ms);
 
 int
 thread_pipeline_disable(uint32_t thread_id,
-	struct obj *obj,
-	const char *pipeline_name);
+			struct rte_swx_pipeline *p);
 
 int
 thread_init(void);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 15/17] examples/pipeline: rework the link CLI command
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (13 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
                     ` (2 subsequent siblings)
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Rework the link CLI command for better alignment with the naming
conventions used in the pipeline I/O specification file. Use the
library linked list of devices and remove the application list.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 81 +++++++++++++----------------------------
 examples/pipeline/obj.c | 16 ++------
 examples/pipeline/obj.h |  4 --
 3 files changed, 29 insertions(+), 72 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index f48ff326be..d56a830fb7 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -106,22 +106,6 @@ parser_read_uint32(uint32_t *value, const char *p)
 	return 0;
 }
 
-static int
-parser_read_uint16(uint16_t *value, const char *p)
-{
-	uint64_t val = 0;
-	int ret = parser_read_uint64(&val, p);
-
-	if (ret < 0)
-		return ret;
-
-	if (val > UINT16_MAX)
-		return -ERANGE;
-
-	*value = val;
-	return 0;
-}
-
 #define PARSE_DELIMITER " \f\n\r\t\v"
 
 static int
@@ -230,16 +214,15 @@ cmd_mempool(char **tokens,
 	}
 }
 
-static const char cmd_link_help[] =
-"link <link_name>\n"
-"   dev <device_name> | port <port_id>\n"
+static const char cmd_ethdev_help[] =
+"ethdev <ethdev_name>\n"
 "   rxq <n_queues> <queue_size> <mempool_name>\n"
 "   txq <n_queues> <queue_size>\n"
 "   promiscuous on | off\n"
 "   [rss <qid_0> ... <qid_n>]\n";
 
 static void
-cmd_link(char **tokens,
+cmd_ethdev(char **tokens,
 	uint32_t n_tokens,
 	char *out,
 	size_t out_size,
@@ -252,65 +235,51 @@ cmd_link(char **tokens,
 
 	memset(&p, 0, sizeof(p));
 
-	if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
+	if ((n_tokens < 11) || (n_tokens > 12 + LINK_RXQ_RSS_MAX)) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
 	name = tokens[1];
 
-	if (strcmp(tokens[2], "dev") == 0)
-		p.dev_name = tokens[3];
-	else if (strcmp(tokens[2], "port") == 0) {
-		p.dev_name = NULL;
-
-		if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
-			return;
-		}
-	} else {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
-		return;
-	}
-
-	if (strcmp(tokens[4], "rxq") != 0) {
+	if (strcmp(tokens[2], "rxq") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
 		return;
 	}
 
-	if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
+	if (parser_read_uint32(&p.rx.n_queues, tokens[3]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
 		return;
 	}
-	if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
+	if (parser_read_uint32(&p.rx.queue_size, tokens[4]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
 		return;
 	}
 
-	p.rx.mempool_name = tokens[7];
+	p.rx.mempool_name = tokens[5];
 
-	if (strcmp(tokens[8], "txq") != 0) {
+	if (strcmp(tokens[6], "txq") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
 		return;
 	}
 
-	if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
+	if (parser_read_uint32(&p.tx.n_queues, tokens[7]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
 		return;
 	}
 
-	if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
+	if (parser_read_uint32(&p.tx.queue_size, tokens[8]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
 		return;
 	}
 
-	if (strcmp(tokens[11], "promiscuous") != 0) {
+	if (strcmp(tokens[9], "promiscuous") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
 		return;
 	}
 
-	if (strcmp(tokens[12], "on") == 0)
+	if (strcmp(tokens[10], "on") == 0)
 		p.promiscuous = 1;
-	else if (strcmp(tokens[12], "off") == 0)
+	else if (strcmp(tokens[10], "off") == 0)
 		p.promiscuous = 0;
 	else {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
@@ -319,10 +288,10 @@ cmd_link(char **tokens,
 
 	/* RSS */
 	p.rx.rss = NULL;
-	if (n_tokens > 13) {
+	if (n_tokens > 11) {
 		uint32_t queue_id, i;
 
-		if (strcmp(tokens[13], "rss") != 0) {
+		if (strcmp(tokens[11], "rss") != 0) {
 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
 			return;
 		}
@@ -330,7 +299,7 @@ cmd_link(char **tokens,
 		p.rx.rss = &rss;
 
 		rss.n_queues = 0;
-		for (i = 14; i < n_tokens; i++) {
+		for (i = 12; i < n_tokens; i++) {
 			if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
 				snprintf(out, out_size, MSG_ARG_INVALID,
 					"queue_id");
@@ -406,10 +375,10 @@ print_link_info(struct link *link, char *out, size_t out_size)
 }
 
 /*
- * link show [<link_name>]
+ * ethdev show [<ethdev_name>]
  */
 static void
-cmd_link_show(char **tokens,
+cmd_ethdev_show(char **tokens,
 	      uint32_t n_tokens,
 	      char *out,
 	      size_t out_size,
@@ -2675,7 +2644,7 @@ cmd_help(char **tokens,
 			"Type 'help <command>' for command details.\n\n"
 			"List of commands:\n"
 			"\tmempool\n"
-			"\tlink\n"
+			"\tethdev\n"
 			"\ttap\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
@@ -2711,8 +2680,8 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (strcmp(tokens[0], "link") == 0) {
-		snprintf(out, out_size, "\n%s\n", cmd_link_help);
+	if (strcmp(tokens[0], "ethdev") == 0) {
+		snprintf(out, out_size, "\n%s\n", cmd_ethdev_help);
 		return;
 	}
 
@@ -2966,13 +2935,13 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 		return;
 	}
 
-	if (strcmp(tokens[0], "link") == 0) {
+	if (strcmp(tokens[0], "ethdev") == 0) {
 		if ((n_tokens >= 2) && (strcmp(tokens[1], "show") == 0)) {
-			cmd_link_show(tokens, n_tokens, out, out_size, obj);
+			cmd_ethdev_show(tokens, n_tokens, out, out_size, obj);
 			return;
 		}
 
-		cmd_link(tokens, n_tokens, out, out_size, obj);
+		cmd_ethdev(tokens, n_tokens, out, out_size, obj);
 		return;
 	}
 
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index d1f519180e..950ab831fb 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -181,7 +181,7 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 	struct mempool *mempool;
 	uint32_t cpu_id, i;
 	int status;
-	uint16_t port_id;
+	uint16_t port_id = 0;
 
 	/* Check input params */
 	if ((name == NULL) ||
@@ -193,16 +193,9 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 		(params->tx.queue_size == 0))
 		return NULL;
 
-	port_id = params->port_id;
-	if (params->dev_name) {
-		status = rte_eth_dev_get_port_by_name(params->dev_name,
-			&port_id);
-
-		if (status)
-			return NULL;
-	} else
-		if (!rte_eth_dev_is_valid_port(port_id))
-			return NULL;
+	status = rte_eth_dev_get_port_by_name(name, &port_id);
+	if (status)
+		return NULL;
 
 	if (rte_eth_dev_info_get(port_id, &port_info) != 0)
 		return NULL;
@@ -315,7 +308,6 @@ link_create(struct obj *obj, const char *name, struct link_params *params)
 	/* Node fill in */
 	strlcpy(link->name, name, sizeof(link->name));
 	link->port_id = port_id;
-	rte_eth_dev_get_name_by_port(port_id, link->dev_name);
 	link->n_rxq = params->rx.n_queues;
 	link->n_txq = params->tx.n_queues;
 
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index e63a9c0e9a..af270a8e57 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -63,9 +63,6 @@ struct link_params_rss {
 };
 
 struct link_params {
-	const char *dev_name;
-	uint16_t port_id; /**< Valid only when *dev_name* is NULL. */
-
 	struct {
 		uint32_t n_queues;
 		uint32_t queue_size;
@@ -84,7 +81,6 @@ struct link_params {
 struct link {
 	TAILQ_ENTRY(link) node;
 	char name[NAME_SIZE];
-	char dev_name[NAME_SIZE];
 	uint16_t port_id;
 	uint32_t n_rxq;
 	uint32_t n_txq;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 16/17] examples/pipelines: remove obsolete tap CLI command
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (14 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-07-28 15:11   ` [PATCH V6 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
  2022-09-15 15:54   ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Thomas Monjalon
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Remove the tap CLI command, as the file descriptor I/O ports of the
pipeline are now configured trough the I/O specification file.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/cli.c | 37 -----------------
 examples/pipeline/obj.c | 89 -----------------------------------------
 examples/pipeline/obj.h | 18 ---------
 3 files changed, 144 deletions(-)

diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c
index d56a830fb7..75c32b9089 100644
--- a/examples/pipeline/cli.c
+++ b/examples/pipeline/cli.c
@@ -466,32 +466,6 @@ cmd_ring(char **tokens,
 	}
 }
 
-static const char cmd_tap_help[] =
-"tap <tap_name>\n";
-
-static void
-cmd_tap(char **tokens,
-	uint32_t n_tokens,
-	char *out,
-	size_t out_size,
-	void *obj)
-{
-	struct tap *tap;
-	char *name;
-
-	if (n_tokens < 2) {
-		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
-		return;
-	}
-	name = tokens[1];
-
-	tap = tap_create(obj, name);
-	if (tap == NULL) {
-		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
-		return;
-	}
-}
-
 static const char cmd_pipeline_codegen_help[] =
 "pipeline codegen <spec_file> <code_file>\n";
 
@@ -2645,7 +2619,6 @@ cmd_help(char **tokens,
 			"List of commands:\n"
 			"\tmempool\n"
 			"\tethdev\n"
-			"\ttap\n"
 			"\tpipeline codegen\n"
 			"\tpipeline libbuild\n"
 			"\tpipeline build\n"
@@ -2690,11 +2663,6 @@ cmd_help(char **tokens,
 		return;
 	}
 
-	if (strcmp(tokens[0], "tap") == 0) {
-		snprintf(out, out_size, "\n%s\n", cmd_tap_help);
-		return;
-	}
-
 	if ((strcmp(tokens[0], "pipeline") == 0) &&
 		(n_tokens == 2) && (strcmp(tokens[1], "codegen") == 0)) {
 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_codegen_help);
@@ -2950,11 +2918,6 @@ cli_process(char *in, char *out, size_t out_size, void *obj)
 		return;
 	}
 
-	if (strcmp(tokens[0], "tap") == 0) {
-		cmd_tap(tokens, n_tokens, out, out_size, obj);
-		return;
-	}
-
 	if (strcmp(tokens[0], "pipeline") == 0) {
 		if ((n_tokens >= 3) &&
 			(strcmp(tokens[1], "codegen") == 0)) {
diff --git a/examples/pipeline/obj.c b/examples/pipeline/obj.c
index 950ab831fb..b7e2316eec 100644
--- a/examples/pipeline/obj.c
+++ b/examples/pipeline/obj.c
@@ -35,11 +35,6 @@ TAILQ_HEAD(link_list, link);
  */
 TAILQ_HEAD(ring_list, ring);
 
-/*
- * tap
- */
-TAILQ_HEAD(tap_list, tap);
-
 /*
  * obj
  */
@@ -47,7 +42,6 @@ struct obj {
 	struct mempool_list mempool_list;
 	struct link_list link_list;
 	struct ring_list ring_list;
-	struct tap_list tap_list;
 };
 
 /*
@@ -416,88 +410,6 @@ ring_find(struct obj *obj, const char *name)
 	return NULL;
 }
 
-/*
- * tap
- */
-#define TAP_DEV		"/dev/net/tun"
-
-struct tap *
-tap_find(struct obj *obj, const char *name)
-{
-	struct tap *tap;
-
-	if (!obj || !name)
-		return NULL;
-
-	TAILQ_FOREACH(tap, &obj->tap_list, node)
-		if (strcmp(tap->name, name) == 0)
-			return tap;
-
-	return NULL;
-}
-
-struct tap *
-tap_next(struct obj *obj, struct tap *tap)
-{
-	return (tap == NULL) ?
-		TAILQ_FIRST(&obj->tap_list) : TAILQ_NEXT(tap, node);
-}
-
-#ifndef RTE_EXEC_ENV_LINUX
-
-struct tap *
-tap_create(struct obj *obj __rte_unused, const char *name __rte_unused)
-{
-	return NULL;
-}
-
-#else
-
-struct tap *
-tap_create(struct obj *obj, const char *name)
-{
-	struct tap *tap;
-	struct ifreq ifr;
-	int fd, status;
-
-	/* Check input params */
-	if ((name == NULL) ||
-		tap_find(obj, name))
-		return NULL;
-
-	/* Resource create */
-	fd = open(TAP_DEV, O_RDWR | O_NONBLOCK);
-	if (fd < 0)
-		return NULL;
-
-	memset(&ifr, 0, sizeof(ifr));
-	ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
-	strlcpy(ifr.ifr_name, name, IFNAMSIZ);
-
-	status = ioctl(fd, TUNSETIFF, (void *) &ifr);
-	if (status < 0) {
-		close(fd);
-		return NULL;
-	}
-
-	/* Node allocation */
-	tap = calloc(1, sizeof(struct tap));
-	if (tap == NULL) {
-		close(fd);
-		return NULL;
-	}
-	/* Node fill in */
-	strlcpy(tap->name, name, sizeof(tap->name));
-	tap->fd = fd;
-
-	/* Node add to list */
-	TAILQ_INSERT_TAIL(&obj->tap_list, tap, node);
-
-	return tap;
-}
-
-#endif
-
 /*
  * obj
  */
@@ -513,7 +425,6 @@ obj_init(void)
 	TAILQ_INIT(&obj->mempool_list);
 	TAILQ_INIT(&obj->link_list);
 	TAILQ_INIT(&obj->ring_list);
-	TAILQ_INIT(&obj->tap_list);
 
 	return obj;
 }
diff --git a/examples/pipeline/obj.h b/examples/pipeline/obj.h
index af270a8e57..8ea1c414c2 100644
--- a/examples/pipeline/obj.h
+++ b/examples/pipeline/obj.h
@@ -121,22 +121,4 @@ ring_create(struct obj *obj,
 struct ring *
 ring_find(struct obj *obj, const char *name);
 
-/*
- * tap
- */
-struct tap {
-	TAILQ_ENTRY(tap) node;
-	char name[NAME_SIZE];
-	int fd;
-};
-
-struct tap *
-tap_find(struct obj *obj, const char *name);
-
-struct tap *
-tap_next(struct obj *obj, struct tap *tap);
-
-struct tap *
-tap_create(struct obj *obj, const char *name);
-
 #endif /* _INCLUDE_OBJ_H_ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH V6 17/17] examples/pipeline: call the code generation and build CLI commands
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (15 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
@ 2022-07-28 15:11   ` Cristian Dumitrescu
  2022-09-15 15:54   ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Thomas Monjalon
  17 siblings, 0 replies; 90+ messages in thread
From: Cristian Dumitrescu @ 2022-07-28 15:11 UTC (permalink / raw)
  To: dev; +Cc: Kamalakannan R .

Update the example CLI scripts with the commands for code generation
and shared object library build.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
---
 examples/pipeline/examples/ethdev.io          | 27 +++++++++
 examples/pipeline/examples/fib.cli            | 44 +++++++-------
 examples/pipeline/examples/hash_func.cli      | 41 ++++++-------
 examples/pipeline/examples/l2fwd.cli          | 44 ++++++++------
 examples/pipeline/examples/l2fwd_macswp.cli   | 44 ++++++++------
 .../pipeline/examples/l2fwd_macswp_pcap.cli   | 35 +++++++----
 examples/pipeline/examples/l2fwd_pcap.cli     | 35 +++++++----
 examples/pipeline/examples/learner.cli        | 43 +++++++-------
 examples/pipeline/examples/meter.cli          | 58 +++++++++++--------
 examples/pipeline/examples/mirroring.cli      | 46 ++++++++-------
 examples/pipeline/examples/pcap.io            | 27 +++++++++
 examples/pipeline/examples/recirculation.cli  | 41 ++++++-------
 examples/pipeline/examples/registers.cli      | 53 +++++++++--------
 examples/pipeline/examples/selector.cli       | 55 +++++++++++-------
 examples/pipeline/examples/varbit.cli         | 41 ++++++-------
 examples/pipeline/examples/vxlan.cli          | 48 ++++++++++-----
 examples/pipeline/examples/vxlan_pcap.cli     | 39 +++++++++----
 17 files changed, 444 insertions(+), 277 deletions(-)
 create mode 100644 examples/pipeline/examples/ethdev.io
 create mode 100644 examples/pipeline/examples/pcap.io

diff --git a/examples/pipeline/examples/ethdev.io b/examples/pipeline/examples/ethdev.io
new file mode 100644
index 0000000000..cf2f3e20bd
--- /dev/null
+++ b/examples/pipeline/examples/ethdev.io
@@ -0,0 +1,27 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2022 Intel Corporation
+
+;
+; Pipeline packet mirroring.
+;
+mirroring slots 4 sessions 64
+
+;
+; Pipeline input ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port in 0 ethdev 0000:18:00.0 rxq 0 bsz 32
+port in 1 ethdev 0000:18:00.1 rxq 0 bsz 32
+port in 2 ethdev 0000:3b:00.0 rxq 0 bsz 32
+port in 3 ethdev 0000:3b:00.1 rxq 0 bsz 32
+
+;
+; Pipeline output ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port out 0 ethdev 0000:18:00.0 txq 0 bsz 32
+port out 1 ethdev 0000:18:00.1 txq 0 bsz 32
+port out 2 ethdev 0000:3b:00.0 txq 0 bsz 32
+port out 3 ethdev 0000:3b:00.1 txq 0 bsz 32
diff --git a/examples/pipeline/examples/fib.cli b/examples/pipeline/examples/fib.cli
index 93ab2b08f8..4e30c1320f 100644
--- a/examples/pipeline/examples/fib.cli
+++ b/examples/pipeline/examples/fib.cli
@@ -1,38 +1,38 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/fib.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/fib.spec /tmp/fib.c
+pipeline libbuild /tmp/fib.c /tmp/fib.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/fib.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/fib.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Initial set of table entries.
 ;
-; The table entries can later be updated at run-time through the CLI commands. Once the application
-; has been successfully started, the command to get the CLI prompt is: telnet 0.0.0.0 8086.
+; The table entries can later be updated at run-time through the CLI commands.
 ;
 pipeline PIPELINE0 table routing_table add ./examples/pipeline/examples/fib_routing_table.txt
 pipeline PIPELINE0 selector nexthop_group_table group add
diff --git a/examples/pipeline/examples/hash_func.cli b/examples/pipeline/examples/hash_func.cli
index d65cd62d17..b2e219e4c9 100644
--- a/examples/pipeline/examples/hash_func.cli
+++ b/examples/pipeline/examples/hash_func.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/hash_func.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/hash_func.spec /tmp/hash_func.c
+pipeline libbuild /tmp/hash_func.c /tmp/hash_func.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/hash_func.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/hash_func.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/l2fwd.cli b/examples/pipeline/examples/l2fwd.cli
index d89caf2d0a..27e37021b9 100644
--- a/examples/pipeline/examples/l2fwd.cli
+++ b/examples/pipeline/examples/l2fwd.cli
@@ -1,25 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd.so io ./examples/pipeline/examples/ethdev.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp.cli b/examples/pipeline/examples/l2fwd_macswp.cli
index 0f2a89ac5b..11bb4543b9 100644
--- a/examples/pipeline/examples/l2fwd_macswp.cli
+++ b/examples/pipeline/examples/l2fwd_macswp.cli
@@ -1,25 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_macswp.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd_macswp.so io ./examples/pipeline/examples/ethdev.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_macswp_pcap.cli b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
index e9656fe3c2..8724dae3b0 100644
--- a/examples/pipeline/examples/l2fwd_macswp_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_macswp_pcap.cli
@@ -1,20 +1,31 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-pipeline PIPELINE0 create 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_macswp_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd_macswp.spec /tmp/l2fwd_macswp.c
+pipeline libbuild /tmp/l2fwd_macswp.c /tmp/l2fwd_macswp.so
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd_macswp.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd_macswp.so io ./examples/pipeline/examples/pcap.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/l2fwd_pcap.cli b/examples/pipeline/examples/l2fwd_pcap.cli
index 23fcb199f1..4db0a0dc56 100644
--- a/examples/pipeline/examples/l2fwd_pcap.cli
+++ b/examples/pipeline/examples/l2fwd_pcap.cli
@@ -1,20 +1,31 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-pipeline PIPELINE0 create 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/l2fwd_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/l2fwd.spec /tmp/l2fwd.c
+pipeline libbuild /tmp/l2fwd.c /tmp/l2fwd.so
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/l2fwd.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/l2fwd.so io ./examples/pipeline/examples/pcap.io numa 0
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/learner.cli b/examples/pipeline/examples/learner.cli
index 688ce34f34..6c8aa3921e 100644
--- a/examples/pipeline/examples/learner.cli
+++ b/examples/pipeline/examples/learner.cli
@@ -1,36 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/learner.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/learner.spec /tmp/learner.c
+pipeline libbuild /tmp/learner.c /tmp/learner.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/learner.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/learner.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
 ;
 thread 1 pipeline PIPELINE0 enable
-
-; Once the application has started, the command to get the CLI prompt is: telnet 0.0.0.0 8086
diff --git a/examples/pipeline/examples/meter.cli b/examples/pipeline/examples/meter.cli
index b29ed24022..c1b88c882a 100644
--- a/examples/pipeline/examples/meter.cli
+++ b/examples/pipeline/examples/meter.cli
@@ -1,31 +1,43 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-; Example command line:
-;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/meter.cli
-
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/meter.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/meter.spec /tmp/meter.c
+pipeline libbuild /tmp/meter.c /tmp/meter.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/meter.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/meter.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 meter profile platinum add cir 46000000 pir 138000000 cbs 1000000 pbs 1000000
 pipeline PIPELINE0 meter meters from 0 to 15 set profile platinum
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/mirroring.cli b/examples/pipeline/examples/mirroring.cli
index 46d57db4ec..1d439e04d3 100644
--- a/examples/pipeline/examples/mirroring.cli
+++ b/examples/pipeline/examples/mirroring.cli
@@ -1,36 +1,38 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/mirroring.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/mirroring.spec /tmp/mirroring.c
+pipeline libbuild /tmp/mirroring.c /tmp/mirroring.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-pipeline PIPELINE0 mirror slots 4 sessions 16
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/mirroring.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/mirroring.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
-; Packet mirroring sessions.
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
 ;
 pipeline PIPELINE0 mirror session 0 port 1 clone fast truncate 0
 pipeline PIPELINE0 mirror session 1 port 2 clone slow truncate 0
diff --git a/examples/pipeline/examples/pcap.io b/examples/pipeline/examples/pcap.io
new file mode 100644
index 0000000000..111f61afae
--- /dev/null
+++ b/examples/pipeline/examples/pcap.io
@@ -0,0 +1,27 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2022 Intel Corporation
+
+;
+; Pipeline packet mirroring.
+;
+mirroring slots 4 sessions 64
+
+;
+; Pipeline input ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port in 0 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 1 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 2 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+port in 3 source mempool MEMPOOL0 file ./examples/pipeline/examples/packet.pcap loop 1 packets 0
+
+;
+; Pipeline output ports.
+;
+; Note: Customize the parameters below to match your setup.
+;
+port out 0 sink file none
+port out 1 sink file none
+port out 2 sink file none
+port out 3 sink file none
diff --git a/examples/pipeline/examples/recirculation.cli b/examples/pipeline/examples/recirculation.cli
index f855c5c327..52d0894f12 100644
--- a/examples/pipeline/examples/recirculation.cli
+++ b/examples/pipeline/examples/recirculation.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2022 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/recirculation.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/recirculation.spec /tmp/recirculation.c
+pipeline libbuild /tmp/recirculation.c /tmp/recirculation.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/recirculation.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/recirculation.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/registers.cli b/examples/pipeline/examples/registers.cli
index 8d026294cb..3516f76a5b 100644
--- a/examples/pipeline/examples/registers.cli
+++ b/examples/pipeline/examples/registers.cli
@@ -1,28 +1,35 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-; Example command line:
-;	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/registers.cli
-
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/registers.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/registers.spec /tmp/registers.c
+pipeline libbuild /tmp/registers.c /tmp/registers.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/registers.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/registers.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/selector.cli b/examples/pipeline/examples/selector.cli
index 123782c57b..f0e251b657 100644
--- a/examples/pipeline/examples/selector.cli
+++ b/examples/pipeline/examples/selector.cli
@@ -1,30 +1,45 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/selector.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/selector.spec /tmp/selector.c
+pipeline libbuild /tmp/selector.c /tmp/selector.so
+
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
 mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
-
-pipeline PIPELINE0 build ./examples/pipeline/examples/selector.spec
-
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/selector.so io ./examples/pipeline/examples/ethdev.io numa 0
+
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 selector s group add
 pipeline PIPELINE0 selector s group member add ./examples/pipeline/examples/selector.txt
 pipeline PIPELINE0 commit
 pipeline PIPELINE0 selector s show
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/varbit.cli b/examples/pipeline/examples/varbit.cli
index 9caeb9ca26..0f89990471 100644
--- a/examples/pipeline/examples/varbit.cli
+++ b/examples/pipeline/examples/varbit.cli
@@ -1,32 +1,33 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/varbit.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
+
 ;
-; Customize the LINK parameters to match your setup.
+; Pipeline code generation & shared object library build.
 ;
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+pipeline codegen ./examples/pipeline/examples/varbit.spec /tmp/varbit.c
+pipeline libbuild /tmp/varbit.c /tmp/varbit.so
 
 ;
-; PIPELINE0 setup.
+; List of DPDK devices.
 ;
-pipeline PIPELINE0 create 0
-
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
-
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/varbit.spec
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/varbit.so io ./examples/pipeline/examples/ethdev.io numa 0
 
 ;
 ; Pipelines-to-threads mapping.
diff --git a/examples/pipeline/examples/vxlan.cli b/examples/pipeline/examples/vxlan.cli
index 444f3f7bd8..1fbd1be6e4 100644
--- a/examples/pipeline/examples/vxlan.cli
+++ b/examples/pipeline/examples/vxlan.cli
@@ -1,27 +1,43 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
-
-link LINK0 dev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK1 dev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK2 dev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
-link LINK3 dev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/vxlan.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
 
-pipeline PIPELINE0 port in 0 link LINK0 rxq 0 bsz 32
-pipeline PIPELINE0 port in 1 link LINK1 rxq 0 bsz 32
-pipeline PIPELINE0 port in 2 link LINK2 rxq 0 bsz 32
-pipeline PIPELINE0 port in 3 link LINK3 rxq 0 bsz 32
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+ethdev 0000:18:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:18:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+ethdev 0000:3b:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
 
-pipeline PIPELINE0 port out 0 link LINK0 txq 0 bsz 32
-pipeline PIPELINE0 port out 1 link LINK1 txq 0 bsz 32
-pipeline PIPELINE0 port out 2 link LINK2 txq 0 bsz 32
-pipeline PIPELINE0 port out 3 link LINK3 txq 0 bsz 32
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/vxlan.so io ./examples/pipeline/examples/ethdev.io numa 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
diff --git a/examples/pipeline/examples/vxlan_pcap.cli b/examples/pipeline/examples/vxlan_pcap.cli
index 83fca8d0d9..adc7f73312 100644
--- a/examples/pipeline/examples/vxlan_pcap.cli
+++ b/examples/pipeline/examples/vxlan_pcap.cli
@@ -1,22 +1,39 @@
 ; SPDX-License-Identifier: BSD-3-Clause
 ; Copyright(c) 2020 Intel Corporation
 
-mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+# Example command line:
+#	./build/examples/dpdk-pipeline -l0-1 -- -s ./examples/pipeline/examples/vxlan_pcap.cli
+#
+# Once the application has started, the command to get the CLI prompt is:
+#	telnet 0.0.0.0 8086
 
-pipeline PIPELINE0 create 0
+;
+; Pipeline code generation & shared object library build.
+;
+pipeline codegen ./examples/pipeline/examples/vxlan.spec /tmp/vxlan.c
+pipeline libbuild /tmp/vxlan.c /tmp/vxlan.so
 
-pipeline PIPELINE0 port in 0 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 1 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 2 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
-pipeline PIPELINE0 port in 3 source MEMPOOL0 ./examples/pipeline/examples/packet.pcap loop 1
+;
+; List of DPDK devices.
+;
+; Note: Customize the parameters below to match your setup.
+;
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
 
-pipeline PIPELINE0 port out 0 sink none
-pipeline PIPELINE0 port out 1 sink none
-pipeline PIPELINE0 port out 2 sink none
-pipeline PIPELINE0 port out 3 sink none
+;
+; List of pipelines.
+;
+pipeline PIPELINE0 build lib /tmp/vxlan.so io ./examples/pipeline/examples/pcap.io numa 0
 
-pipeline PIPELINE0 build ./examples/pipeline/examples/vxlan.spec
+;
+; Initial set of table entries.
+;
+; The table entries can later be updated at run-time through the CLI commands.
+;
 pipeline PIPELINE0 table vxlan_table add ./examples/pipeline/examples/vxlan_table.txt
 pipeline PIPELINE0 commit
 
+;
+; Pipelines-to-threads mapping.
+;
 thread 1 pipeline PIPELINE0 enable
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* RE: [PATCH V5 01/17] pipeline: add pipeline name
  2022-07-28  8:22         ` [PATCH V5 01/17] pipeline: add pipeline name Bruce Richardson
@ 2022-07-28 15:17           ` Dumitrescu, Cristian
  0 siblings, 0 replies; 90+ messages in thread
From: Dumitrescu, Cristian @ 2022-07-28 15:17 UTC (permalink / raw)
  To: Richardson, Bruce; +Cc: dev, R, Kamalakannan



> -----Original Message-----
> From: Richardson, Bruce <bruce.richardson@intel.com>
> Sent: Thursday, July 28, 2022 9:22 AM
> To: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>
> Cc: dev@dpdk.org; R, Kamalakannan <kamalakannan.r@intel.com>
> Subject: Re: [PATCH V5 01/17] pipeline: add pipeline name
> 
> On Wed, Jul 27, 2022 at 11:01:16PM +0000, Cristian Dumitrescu wrote:
> > Add an unique name to every pipeline. This enables the library to
> > maintain a list of the existing pipeline objects, which can be
> > queried by the application.
> >
> > Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> > Signed-off-by: Kamalakannan R. <kamalakannan.r@intel.com>
> > ---
> I really think this patchset could do with a cover letter. Since you are
> now on v5, it would be nice to have a cover-letter where the differences
> between each of the patch versions are called out. A cover-letter is also
> nice to outline the overall scope of the changes rather than asking
> reviewers to go through the set patch by patch to see what is in there.
> 
> Thanks,
> /Bruce

Just sent the cover letter with V6, thanks.

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH V6 00/17] pipeline: pipeline configuration and build improvements
  2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
                     ` (16 preceding siblings ...)
  2022-07-28 15:11   ` [PATCH V6 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
@ 2022-09-15 15:54   ` Thomas Monjalon
  17 siblings, 0 replies; 90+ messages in thread
From: Thomas Monjalon @ 2022-09-15 15:54 UTC (permalink / raw)
  To: Cristian Dumitrescu; +Cc: dev

28/07/2022 17:11, Cristian Dumitrescu:
> The sequence of steps to build a SWX pipeline object are:
> 
> 1. Create the specification file (pipeline.p4 -> pipeline.spec): This text file represents the
>    pipeline program that is typically generated by the P4 compiler or sometimes manually created.
> 
> 2. Generate the C source code file (pipeline.spec -> pipeline.c): The C file contains a C function
>    for every pipeline action and several C functions for the pipeline main program. It allows the C
>    compiler to generate optimized code by having access to the entire pipeline program rather than
>    using the small pre-build functions corresponding to the individual instructions
> 
> 3. Build the shared object library (pipeline.c -> pipeline.o -> pipeline.so).
> 
> 4. Load the shared object library (pipeline.so): At initialization, the pipeline object is “patched”
>    with the optimized C functions from the shared object library.
> 
> Previously, steps 2., 3. and 4. were implemented under the hood by the pipeline library at the
> initialization time in a completely hard-coded and non-customizable way. The user was not able to
> select the C compiler (GCC was assumed), the compiler version, the build flags, the file locations,
> etc. The code generation (step 2.) and library build (step 3.) were done on-the-fly at init and
> could potentially fail for many setup related reasons.
> 
> Now, this process is no longer done under the hood by the pipeline library and the individual steps
> are explicitly supported by the API functions. The code generation (step 2.) is done off-line at any
> time before the pipeline execution. The library build (step 3.) is also done off-line and is now
> fully customizable by the user, who is able to gracefully access the generated C code and decide on
> the various build options.
> 
> We also take the opportunity to streamline the pipeline I/O port configuration by introducing an I/O
> specification file. Essentially, the pipeline is now configured and build based on two files:
> 
> a) The shared object library file (pipeline.so): It defines how the packets are processed by the
>    program through tables and actions; the same P4 program can be executed by many pipelines.
> 
> b) The I/O specification file (pipeline.io): High level text file defining how the packets are
>    received and transmitted by the pipeline; this is not part of the P4 program, which is completely
>    agnostic about the pipeline I/O ports. This is defined differently for each pipeline object when
>    initialized.

Series applied, thanks.




^ permalink raw reply	[flat|nested] 90+ messages in thread

end of thread, other threads:[~2022-09-15 15:54 UTC | newest]

Thread overview: 90+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-18 13:07 [PATCH 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
2022-07-18 13:07 ` [PATCH 2/9] pipeline: add pipeline specification data structure Cristian Dumitrescu
2022-07-18 13:07 ` [PATCH 3/9] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
2022-07-18 13:07 ` [PATCH 4/9] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
2022-07-18 13:07 ` [PATCH 5/9] pipeline: add API for pipeline code generation Cristian Dumitrescu
2022-07-18 13:07 ` [PATCH 6/9] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
2022-07-18 13:07 ` [PATCH 7/9] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
2022-07-18 13:07 ` [PATCH 8/9] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
2022-07-18 13:07 ` [PATCH 9/9] examples/pipeline: call CLI commands for code generation and build Cristian Dumitrescu
2022-07-18 13:25 ` [PATCH V2 1/9] pipeline: move specification data structures to internal header Cristian Dumitrescu
2022-07-18 13:25   ` [PATCH V2 2/9] pipeline: add pipeline specification data structure Cristian Dumitrescu
2022-07-18 13:25   ` [PATCH V2 3/9] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
2022-07-18 13:25   ` [PATCH V2 4/9] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
2022-07-18 13:25   ` [PATCH V2 5/9] pipeline: add API for pipeline code generation Cristian Dumitrescu
2022-07-18 13:26   ` [PATCH V2 6/9] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
2022-07-18 13:26   ` [PATCH V2 7/9] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
2022-07-18 13:26   ` [PATCH V2 8/9] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
2022-07-18 13:26   ` [PATCH V2 9/9] examples/pipeline: call CLI commands for code generation and build Cristian Dumitrescu
2022-07-27 22:36   ` [PATCH V3 01/17] pipeline: add pipeline name Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
2022-07-27 22:36     ` [PATCH V3 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
2022-07-27 22:54     ` [PATCH V4 01/17] pipeline: add pipeline name Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
2022-07-27 22:54       ` [PATCH V4 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
2022-07-27 23:01       ` [PATCH V5 01/17] pipeline: add pipeline name Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
2022-07-27 23:01         ` [PATCH V5 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
2022-07-28  8:22         ` [PATCH V5 01/17] pipeline: add pipeline name Bruce Richardson
2022-07-28 15:17           ` Dumitrescu, Cristian
2022-07-28 15:11 ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 01/17] pipeline: add pipeline name Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 02/17] pipeline: move specification data structures to internal header Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 03/17] pipeline: add pipeline specification data structure Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 04/17] pipeline: rework the specification file-based pipeline build Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 05/17] pipeline: generate the code for pipeline specification structure Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 06/17] pipeline: add support for pipeline I/O specification Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 07/17] pipeline: add API for pipeline code generation Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 08/17] pipeline: add API for shared library-based pipeline build Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 09/17] examples/pipeline: add CLI command for pipeline code generation Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 10/17] examples/pipeline: add CLI command for shared library build Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 11/17] examples/pipeline: remove the obsolete pipeline create CLI command Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 12/17] examples/pipeline: remove the obsolete port configuration CLI commands Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 13/17] examples/pipeline: remove the obsolete mirroring configuration CLI command Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 14/17] examples/pipeline: use the pipeline name query API Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 15/17] examples/pipeline: rework the link CLI command Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 16/17] examples/pipelines: remove obsolete tap " Cristian Dumitrescu
2022-07-28 15:11   ` [PATCH V6 17/17] examples/pipeline: call the code generation and build CLI commands Cristian Dumitrescu
2022-09-15 15:54   ` [PATCH V6 00/17] pipeline: pipeline configuration and build improvements Thomas Monjalon

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.