[V2,6/9] pipeline: add API for shared library-based pipeline build

Message ID 20220718132603.339314-6-cristian.dumitrescu@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers
Series [V2,1/9] pipeline: move specification data structures to internal header |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Cristian Dumitrescu July 18, 2022, 1:26 p.m. UTC
  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(-)
  

Patch

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;
 };