get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/114357/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 114357,
    "url": "https://patches.dpdk.org/api/patches/114357/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20220728151147.603265-5-cristian.dumitrescu@intel.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20220728151147.603265-5-cristian.dumitrescu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20220728151147.603265-5-cristian.dumitrescu@intel.com",
    "date": "2022-07-28T15:11:34",
    "name": "[V6,04/17] pipeline: rework the specification file-based pipeline build",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "4ac61efff7af824d2cede11fe01100527f58a5a0",
    "submitter": {
        "id": 19,
        "url": "https://patches.dpdk.org/api/people/19/?format=api",
        "name": "Cristian Dumitrescu",
        "email": "cristian.dumitrescu@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20220728151147.603265-5-cristian.dumitrescu@intel.com/mbox/",
    "series": [
        {
            "id": 24117,
            "url": "https://patches.dpdk.org/api/series/24117/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=24117",
            "date": "2022-07-28T15:11:30",
            "name": "pipeline: pipeline configuration and build improvements",
            "version": 6,
            "mbox": "https://patches.dpdk.org/series/24117/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/114357/comments/",
    "check": "success",
    "checks": "https://patches.dpdk.org/api/patches/114357/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 6958FA00C5;\n\tThu, 28 Jul 2022 17:12:19 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 278EA42BCD;\n\tThu, 28 Jul 2022 17:11:59 +0200 (CEST)",
            "from mga14.intel.com (mga14.intel.com [192.55.52.115])\n by mails.dpdk.org (Postfix) with ESMTP id 2542142BAE\n for <dev@dpdk.org>; Thu, 28 Jul 2022 17:11:54 +0200 (CEST)",
            "from orsmga001.jf.intel.com ([10.7.209.18])\n by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 28 Jul 2022 08:11:54 -0700",
            "from silpixa00400573.ir.intel.com (HELO\n silpixa00400573.ger.corp.intel.com.) ([10.237.223.157])\n by orsmga001.jf.intel.com with ESMTP; 28 Jul 2022 08:11:53 -0700"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1659021115; x=1690557115;\n h=from:to:cc:subject:date:message-id:in-reply-to:\n references:mime-version:content-transfer-encoding;\n bh=/Tc0YNchNec0Ple4MywKk1sdw752M8EjNw570gyqv2c=;\n b=UKWpPhjULf7IFYJ+jH/ltb57ygQHmIXwwun06mam3M2XXn32s/+P5CdX\n 1dWljFo1yS8A+HziSPxML4hcT9zYHJ/0cSC5zHPud1bb8tIynLytr/ddV\n E+amRB0CqGl2vfwIsx7Hx9YOp4hMyCLb2HbMOm36dPYzsOooEtpc3KGv5\n wOy2C1tU/j6+2B20CA9Mhsh0fIKzxxUK5Pbr+1KhwCSz+oRs8/k4v59hi\n nNtWarszfXZ/if2MxQ+coroB1k2Bv6pFvop8v6+5Zho0S6Sm30cQ4EttH\n zmNoBFWpbnJaTOnlZvjSjVLQc7JhXa7hPKbuDbiqEPEz5pXHiMkqiT/x2 Q==;",
        "X-IronPort-AV": [
            "E=McAfee;i=\"6400,9594,10422\"; a=\"288547373\"",
            "E=Sophos;i=\"5.93,198,1654585200\"; d=\"scan'208\";a=\"288547373\"",
            "E=Sophos;i=\"5.93,198,1654585200\"; d=\"scan'208\";a=\"633727161\""
        ],
        "X-ExtLoop1": "1",
        "From": "Cristian Dumitrescu <cristian.dumitrescu@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "\"Kamalakannan R .\" <kamalakannan.r@intel.com>",
        "Subject": "[PATCH V6 04/17] pipeline: rework the specification file-based\n pipeline build",
        "Date": "Thu, 28 Jul 2022 15:11:34 +0000",
        "Message-Id": "<20220728151147.603265-5-cristian.dumitrescu@intel.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20220728151147.603265-1-cristian.dumitrescu@intel.com>",
        "References": "<20220718130713.339003-1-cristian.dumitrescu@intel.com>\n <20220728151147.603265-1-cristian.dumitrescu@intel.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "Rework the specification file-based pipeline build operation to first\nparse the specification file into the previously introduced pipeline\nspecification data structure, then use this structure to configure\nand build the pipeline.\n\nSigned-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>\nSigned-off-by: Kamalakannan R. <kamalakannan.r@intel.com>\n---\n lib/pipeline/rte_swx_pipeline_spec.c | 478 +++++++++++++++++++++------\n lib/pipeline/rte_swx_pipeline_spec.h |   9 +\n 2 files changed, 385 insertions(+), 102 deletions(-)",
    "diff": "diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c\nindex 642091b678..62929a9da6 100644\n--- a/lib/pipeline/rte_swx_pipeline_spec.c\n+++ b/lib/pipeline/rte_swx_pipeline_spec.c\n@@ -2103,11 +2103,10 @@ pipeline_spec_free(struct pipeline_spec *s)\n \tmemset(s, 0, sizeof(struct pipeline_spec));\n }\n \n-int\n-rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n-\t\t\t\t FILE *spec,\n-\t\t\t\t uint32_t *err_line,\n-\t\t\t\t const char **err_msg)\n+struct pipeline_spec *\n+pipeline_spec_parse(FILE *spec,\n+\t\t    uint32_t *err_line,\n+\t\t    const char **err_msg)\n {\n \tstruct extobj_spec extobj_spec = {0};\n \tstruct struct_spec struct_spec = {0};\n@@ -2120,26 +2119,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \tstruct regarray_spec regarray_spec = {0};\n \tstruct metarray_spec metarray_spec = {0};\n \tstruct apply_spec apply_spec = {0};\n-\tuint32_t n_lines;\n+\tstruct pipeline_spec *s = NULL;\n+\tuint32_t n_lines = 0;\n \tuint32_t block_mask = 0;\n-\tint status;\n+\tint status = 0;\n \n \t/* Check the input arguments. */\n-\tif (!p) {\n+\tif (!spec) {\n \t\tif (err_line)\n-\t\t\t*err_line = 0;\n+\t\t\t*err_line = n_lines;\n \t\tif (err_msg)\n-\t\t\t*err_msg = \"Null pipeline argument.\";\n+\t\t\t*err_msg = \"Invalid input argument.\";\n \t\tstatus = -EINVAL;\n \t\tgoto error;\n \t}\n \n-\tif (!spec) {\n+\t/* Memory allocation. */\n+\ts = calloc(sizeof(struct pipeline_spec), 1);\n+\tif (!s) {\n \t\tif (err_line)\n-\t\t\t*err_line = 0;\n+\t\t\t*err_line = n_lines;\n \t\tif (err_msg)\n-\t\t\t*err_msg = \"Null specification file argument.\";\n-\t\tstatus = -EINVAL;\n+\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\tstatus = -ENOMEM;\n \t\tgoto error;\n \t}\n \n@@ -2200,6 +2202,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \n \t\t/* struct block. */\n \t\tif (block_mask & (1 << STRUCT_BLOCK)) {\n+\t\t\tstruct struct_spec *new_structs;\n+\n \t\t\tstatus = struct_block_parse(&struct_spec,\n \t\t\t\t\t\t    &block_mask,\n \t\t\t\t\t\t    tokens,\n@@ -2214,26 +2218,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\t\tcontinue;\n \n \t\t\t/* End of block. */\n-\t\t\tstatus = rte_swx_pipeline_struct_type_register(p,\n-\t\t\t\tstruct_spec.name,\n-\t\t\t\tstruct_spec.fields,\n-\t\t\t\tstruct_spec.n_fields,\n-\t\t\t\tstruct_spec.varbit);\n-\t\t\tif (status) {\n+\t\t\tnew_structs = realloc(s->structs,\n+\t\t\t\t\t      (s->n_structs + 1) * sizeof(struct struct_spec));\n+\t\t\tif (!new_structs) {\n \t\t\t\tif (err_line)\n \t\t\t\t\t*err_line = n_lines;\n \t\t\t\tif (err_msg)\n-\t\t\t\t\t*err_msg = \"Struct registration error.\";\n+\t\t\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\t\t\tstatus = -ENOMEM;\n \t\t\t\tgoto error;\n \t\t\t}\n \n-\t\t\tstruct_spec_free(&struct_spec);\n+\t\t\ts->structs = new_structs;\n+\t\t\tmemcpy(&s->structs[s->n_structs], &struct_spec, sizeof(struct struct_spec));\n+\t\t\ts->n_structs++;\n+\t\t\tmemset(&struct_spec, 0, sizeof(struct struct_spec));\n \n \t\t\tcontinue;\n \t\t}\n \n \t\t/* action block. */\n \t\tif (block_mask & (1 << ACTION_BLOCK)) {\n+\t\t\tstruct action_spec *new_actions;\n+\n \t\t\tstatus = action_block_parse(&action_spec,\n \t\t\t\t\t\t    &block_mask,\n \t\t\t\t\t\t    tokens,\n@@ -2248,26 +2255,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\t\tcontinue;\n \n \t\t\t/* End of block. */\n-\t\t\tstatus = rte_swx_pipeline_action_config(p,\n-\t\t\t\taction_spec.name,\n-\t\t\t\taction_spec.args_struct_type_name,\n-\t\t\t\taction_spec.instructions,\n-\t\t\t\taction_spec.n_instructions);\n-\t\t\tif (status) {\n+\t\t\tnew_actions = realloc(s->actions,\n+\t\t\t\t\t      (s->n_actions + 1) * sizeof(struct action_spec));\n+\t\t\tif (!new_actions) {\n \t\t\t\tif (err_line)\n \t\t\t\t\t*err_line = n_lines;\n \t\t\t\tif (err_msg)\n-\t\t\t\t\t*err_msg = \"Action config error.\";\n+\t\t\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\t\t\tstatus = -ENOMEM;\n \t\t\t\tgoto error;\n \t\t\t}\n \n-\t\t\taction_spec_free(&action_spec);\n+\t\t\ts->actions = new_actions;\n+\t\t\tmemcpy(&s->actions[s->n_actions], &action_spec, sizeof(struct action_spec));\n+\t\t\ts->n_actions++;\n+\t\t\tmemset(&action_spec, 0, sizeof(struct action_spec));\n \n \t\t\tcontinue;\n \t\t}\n \n \t\t/* table block. */\n \t\tif (block_mask & (1 << TABLE_BLOCK)) {\n+\t\t\tstruct table_spec *new_tables;\n+\n \t\t\tstatus = table_block_parse(&table_spec,\n \t\t\t\t\t\t   &block_mask,\n \t\t\t\t\t\t   tokens,\n@@ -2282,27 +2292,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\t\tcontinue;\n \n \t\t\t/* End of block. */\n-\t\t\tstatus = rte_swx_pipeline_table_config(p,\n-\t\t\t\ttable_spec.name,\n-\t\t\t\t&table_spec.params,\n-\t\t\t\ttable_spec.recommended_table_type_name,\n-\t\t\t\ttable_spec.args,\n-\t\t\t\ttable_spec.size);\n-\t\t\tif (status) {\n+\t\t\tnew_tables = realloc(s->tables,\n+\t\t\t\t\t     (s->n_tables + 1) * sizeof(struct table_spec));\n+\t\t\tif (!new_tables) {\n \t\t\t\tif (err_line)\n \t\t\t\t\t*err_line = n_lines;\n \t\t\t\tif (err_msg)\n-\t\t\t\t\t*err_msg = \"Table configuration error.\";\n+\t\t\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\t\t\tstatus = -ENOMEM;\n \t\t\t\tgoto error;\n \t\t\t}\n \n-\t\t\ttable_spec_free(&table_spec);\n+\t\t\ts->tables = new_tables;\n+\t\t\tmemcpy(&s->tables[s->n_tables], &table_spec, sizeof(struct table_spec));\n+\t\t\ts->n_tables++;\n+\t\t\tmemset(&table_spec, 0, sizeof(struct table_spec));\n \n \t\t\tcontinue;\n \t\t}\n \n \t\t/* selector block. */\n \t\tif (block_mask & (1 << SELECTOR_BLOCK)) {\n+\t\t\tstruct selector_spec *new_selectors;\n+\n \t\t\tstatus = selector_block_parse(&selector_spec,\n \t\t\t\t\t\t      &block_mask,\n \t\t\t\t\t\t      tokens,\n@@ -2317,24 +2329,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\t\tcontinue;\n \n \t\t\t/* End of block. */\n-\t\t\tstatus = rte_swx_pipeline_selector_config(p,\n-\t\t\t\tselector_spec.name,\n-\t\t\t\t&selector_spec.params);\n-\t\t\tif (status) {\n+\t\t\tnew_selectors = realloc(s->selectors,\n+\t\t\t\t(s->n_selectors + 1) * sizeof(struct selector_spec));\n+\t\t\tif (!new_selectors) {\n \t\t\t\tif (err_line)\n \t\t\t\t\t*err_line = n_lines;\n \t\t\t\tif (err_msg)\n-\t\t\t\t\t*err_msg = \"Selector configuration error.\";\n+\t\t\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\t\t\tstatus = -ENOMEM;\n \t\t\t\tgoto error;\n \t\t\t}\n \n-\t\t\tselector_spec_free(&selector_spec);\n+\t\t\ts->selectors = new_selectors;\n+\t\t\tmemcpy(&s->selectors[s->n_selectors],\n+\t\t\t       &selector_spec,\n+\t\t\t       sizeof(struct selector_spec));\n+\t\t\ts->n_selectors++;\n+\t\t\tmemset(&selector_spec, 0, sizeof(struct selector_spec));\n \n \t\t\tcontinue;\n \t\t}\n \n \t\t/* learner block. */\n \t\tif (block_mask & (1 << LEARNER_BLOCK)) {\n+\t\t\tstruct learner_spec *new_learners;\n+\n \t\t\tstatus = learner_block_parse(&learner_spec,\n \t\t\t\t\t\t     &block_mask,\n \t\t\t\t\t\t     tokens,\n@@ -2349,27 +2368,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\t\tcontinue;\n \n \t\t\t/* End of block. */\n-\t\t\tstatus = rte_swx_pipeline_learner_config(p,\n-\t\t\t\tlearner_spec.name,\n-\t\t\t\t&learner_spec.params,\n-\t\t\t\tlearner_spec.size,\n-\t\t\t\tlearner_spec.timeout,\n-\t\t\t\tlearner_spec.n_timeouts);\n-\t\t\tif (status) {\n+\t\t\tnew_learners = realloc(s->learners,\n+\t\t\t\t\t       (s->n_learners + 1) * sizeof(struct learner_spec));\n+\t\t\tif (!new_learners) {\n \t\t\t\tif (err_line)\n \t\t\t\t\t*err_line = n_lines;\n \t\t\t\tif (err_msg)\n-\t\t\t\t\t*err_msg = \"Learner table configuration error.\";\n+\t\t\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\t\t\tstatus = -ENOMEM;\n \t\t\t\tgoto error;\n \t\t\t}\n \n-\t\t\tlearner_spec_free(&learner_spec);\n+\t\t\ts->learners = new_learners;\n+\t\t\tmemcpy(&s->learners[s->n_learners],\n+\t\t\t       &learner_spec,\n+\t\t\t       sizeof(struct learner_spec));\n+\t\t\ts->n_learners++;\n+\t\t\tmemset(&learner_spec, 0, sizeof(struct learner_spec));\n \n \t\t\tcontinue;\n \t\t}\n \n \t\t/* apply block. */\n \t\tif (block_mask & (1 << APPLY_BLOCK)) {\n+\t\t\tstruct apply_spec *new_apply;\n+\n \t\t\tstatus = apply_block_parse(&apply_spec,\n \t\t\t\t\t\t   &block_mask,\n \t\t\t\t\t\t   tokens,\n@@ -2384,24 +2407,28 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\t\tcontinue;\n \n \t\t\t/* End of block. */\n-\t\t\tstatus = rte_swx_pipeline_instructions_config(p,\n-\t\t\t\tapply_spec.instructions,\n-\t\t\t\tapply_spec.n_instructions);\n-\t\t\tif (status) {\n+\t\t\tnew_apply = realloc(s->apply, (s->n_apply + 1) * sizeof(struct apply_spec));\n+\t\t\tif (!new_apply) {\n \t\t\t\tif (err_line)\n \t\t\t\t\t*err_line = n_lines;\n \t\t\t\tif (err_msg)\n-\t\t\t\t\t*err_msg = \"Pipeline instructions err.\";\n+\t\t\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\t\t\tstatus = -ENOMEM;\n \t\t\t\tgoto error;\n \t\t\t}\n \n-\t\t\tapply_spec_free(&apply_spec);\n+\t\t\ts->apply = new_apply;\n+\t\t\tmemcpy(&s->apply[s->n_apply], &apply_spec, sizeof(struct apply_spec));\n+\t\t\ts->n_apply++;\n+\t\t\tmemset(&apply_spec, 0, sizeof(struct apply_spec));\n \n \t\t\tcontinue;\n \t\t}\n \n \t\t/* extobj. */\n \t\tif (!strcmp(tokens[0], \"extobj\")) {\n+\t\t\tstruct extobj_spec *new_extobjs;\n+\n \t\t\tstatus = extobj_statement_parse(&extobj_spec,\n \t\t\t\t\t\t\ttokens,\n \t\t\t\t\t\t\tn_tokens,\n@@ -2411,19 +2438,21 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\tif (status)\n \t\t\t\tgoto error;\n \n-\t\t\tstatus = rte_swx_pipeline_extern_object_config(p,\n-\t\t\t\textobj_spec.name,\n-\t\t\t\textobj_spec.extern_type_name,\n-\t\t\t\textobj_spec.pragma);\n-\t\t\tif (status) {\n+\t\t\tnew_extobjs = realloc(s->extobjs,\n+\t\t\t\t\t      (s->n_extobjs + 1) * sizeof(struct extobj_spec));\n+\t\t\tif (!new_extobjs) {\n \t\t\t\tif (err_line)\n \t\t\t\t\t*err_line = n_lines;\n \t\t\t\tif (err_msg)\n-\t\t\t\t\t*err_msg = \"Extern object config err.\";\n+\t\t\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\t\t\tstatus = -ENOMEM;\n \t\t\t\tgoto error;\n \t\t\t}\n \n-\t\t\textobj_spec_free(&extobj_spec);\n+\t\t\ts->extobjs = new_extobjs;\n+\t\t\tmemcpy(&s->extobjs[s->n_extobjs], &extobj_spec, sizeof(struct extobj_spec));\n+\t\t\ts->n_extobjs++;\n+\t\t\tmemset(&extobj_spec, 0, sizeof(struct extobj_spec));\n \n \t\t\tcontinue;\n \t\t}\n@@ -2445,6 +2474,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \n \t\t/* header. */\n \t\tif (!strcmp(tokens[0], \"header\")) {\n+\t\t\tstruct header_spec *new_headers;\n+\n \t\t\tstatus = header_statement_parse(&header_spec,\n \t\t\t\t\t\t\ttokens,\n \t\t\t\t\t\t\tn_tokens,\n@@ -2454,24 +2485,29 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\tif (status)\n \t\t\t\tgoto error;\n \n-\t\t\tstatus = rte_swx_pipeline_packet_header_register(p,\n-\t\t\t\theader_spec.name,\n-\t\t\t\theader_spec.struct_type_name);\n-\t\t\tif (status) {\n+\t\t\tnew_headers = realloc(s->headers,\n+\t\t\t\t\t      (s->n_headers + 1) * sizeof(struct header_spec));\n+\t\t\tif (!new_headers) {\n \t\t\t\tif (err_line)\n \t\t\t\t\t*err_line = n_lines;\n \t\t\t\tif (err_msg)\n-\t\t\t\t\t*err_msg = \"Header registration error.\";\n+\t\t\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\t\t\tstatus = -ENOMEM;\n \t\t\t\tgoto error;\n \t\t\t}\n \n-\t\t\theader_spec_free(&header_spec);\n+\t\t\ts->headers = new_headers;\n+\t\t\tmemcpy(&s->headers[s->n_headers], &header_spec, sizeof(struct header_spec));\n+\t\t\ts->n_headers++;\n+\t\t\tmemset(&header_spec, 0, sizeof(struct header_spec));\n \n \t\t\tcontinue;\n \t\t}\n \n \t\t/* metadata. */\n \t\tif (!strcmp(tokens[0], \"metadata\")) {\n+\t\t\tstruct metadata_spec *new_metadata;\n+\n \t\t\tstatus = metadata_statement_parse(&metadata_spec,\n \t\t\t\t\t\t\t  tokens,\n \t\t\t\t\t\t\t  n_tokens,\n@@ -2481,17 +2517,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\tif (status)\n \t\t\t\tgoto error;\n \n-\t\t\tstatus = rte_swx_pipeline_packet_metadata_register(p,\n-\t\t\t\tmetadata_spec.struct_type_name);\n-\t\t\tif (status) {\n+\t\t\tnew_metadata = realloc(s->metadata,\n+\t\t\t\t\t       (s->n_metadata + 1) * sizeof(struct metadata_spec));\n+\t\t\tif (!new_metadata) {\n \t\t\t\tif (err_line)\n \t\t\t\t\t*err_line = n_lines;\n \t\t\t\tif (err_msg)\n-\t\t\t\t\t*err_msg = \"Meta-data reg err.\";\n+\t\t\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\t\t\tstatus = -ENOMEM;\n \t\t\t\tgoto error;\n \t\t\t}\n \n-\t\t\tmetadata_spec_free(&metadata_spec);\n+\t\t\ts->metadata = new_metadata;\n+\t\t\tmemcpy(&s->metadata[s->n_metadata],\n+\t\t\t       &metadata_spec,\n+\t\t\t       sizeof(struct metadata_spec));\n+\t\t\ts->n_metadata++;\n+\t\t\tmemset(&metadata_spec, 0, sizeof(struct metadata_spec));\n \n \t\t\tcontinue;\n \t\t}\n@@ -2558,6 +2600,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \n \t\t/* regarray. */\n \t\tif (!strcmp(tokens[0], \"regarray\")) {\n+\t\t\tstruct regarray_spec *new_regarrays;\n+\n \t\t\tstatus = regarray_statement_parse(&regarray_spec,\n \t\t\t\t\t\t\t  tokens,\n \t\t\t\t\t\t\t  n_tokens,\n@@ -2567,25 +2611,31 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\tif (status)\n \t\t\t\tgoto error;\n \n-\t\t\tstatus = rte_swx_pipeline_regarray_config(p,\n-\t\t\t\tregarray_spec.name,\n-\t\t\t\tregarray_spec.size,\n-\t\t\t\tregarray_spec.init_val);\n-\t\t\tif (status) {\n+\t\t\tnew_regarrays = realloc(s->regarrays,\n+\t\t\t\t(s->n_regarrays + 1) * sizeof(struct regarray_spec));\n+\t\t\tif (!new_regarrays) {\n \t\t\t\tif (err_line)\n \t\t\t\t\t*err_line = n_lines;\n \t\t\t\tif (err_msg)\n-\t\t\t\t\t*err_msg = \"Register array configuration error.\";\n+\t\t\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\t\t\tstatus = -ENOMEM;\n \t\t\t\tgoto error;\n \t\t\t}\n \n-\t\t\tregarray_spec_free(&regarray_spec);\n+\t\t\ts->regarrays = new_regarrays;\n+\t\t\tmemcpy(&s->regarrays[s->n_regarrays],\n+\t\t\t       &regarray_spec,\n+\t\t\t       sizeof(struct regarray_spec));\n+\t\t\ts->n_regarrays++;\n+\t\t\tmemset(&regarray_spec, 0, sizeof(struct regarray_spec));\n \n \t\t\tcontinue;\n \t\t}\n \n \t\t/* metarray. */\n \t\tif (!strcmp(tokens[0], \"metarray\")) {\n+\t\t\tstruct metarray_spec *new_metarrays;\n+\n \t\t\tstatus = metarray_statement_parse(&metarray_spec,\n \t\t\t\t\t\t\t  tokens,\n \t\t\t\t\t\t\t  n_tokens,\n@@ -2595,18 +2645,23 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\t\tif (status)\n \t\t\t\tgoto error;\n \n-\t\t\tstatus = rte_swx_pipeline_metarray_config(p,\n-\t\t\t\tmetarray_spec.name,\n-\t\t\t\tmetarray_spec.size);\n-\t\t\tif (status) {\n+\t\t\tnew_metarrays = realloc(s->metarrays,\n+\t\t\t\t(s->n_metarrays + 1) * sizeof(struct metarray_spec));\n+\t\t\tif (!new_metarrays) {\n \t\t\t\tif (err_line)\n \t\t\t\t\t*err_line = n_lines;\n \t\t\t\tif (err_msg)\n-\t\t\t\t\t*err_msg = \"Meter array configuration error.\";\n+\t\t\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\t\t\tstatus = -ENOMEM;\n \t\t\t\tgoto error;\n \t\t\t}\n \n-\t\t\tmetarray_spec_free(&metarray_spec);\n+\t\t\ts->metarrays = new_metarrays;\n+\t\t\tmemcpy(&s->metarrays[s->n_metarrays],\n+\t\t\t       &metarray_spec,\n+\t\t\t       sizeof(struct metarray_spec));\n+\t\t\ts->n_metarrays++;\n+\t\t\tmemset(&metarray_spec, 0, sizeof(struct metarray_spec));\n \n \t\t\tcontinue;\n \t\t}\n@@ -2644,17 +2699,7 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \t\tgoto error;\n \t}\n \n-\t/* Pipeline build. */\n-\tstatus = rte_swx_pipeline_build(p);\n-\tif (status) {\n-\t\tif (err_line)\n-\t\t\t*err_line = n_lines;\n-\t\tif (err_msg)\n-\t\t\t*err_msg = \"Pipeline build error.\";\n-\t\tgoto error;\n-\t}\n-\n-\treturn 0;\n+\treturn s;\n \n error:\n \textobj_spec_free(&extobj_spec);\n@@ -2668,5 +2713,234 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \tregarray_spec_free(&regarray_spec);\n \tmetarray_spec_free(&metarray_spec);\n \tapply_spec_free(&apply_spec);\n+\tpipeline_spec_free(s);\n+\n+\treturn NULL;\n+}\n+\n+int\n+pipeline_spec_configure(struct rte_swx_pipeline *p,\n+\t\t\tstruct pipeline_spec *s,\n+\t\t\tconst char **err_msg)\n+{\n+\tuint32_t i;\n+\tint status = 0;\n+\n+\t/* extobj. */\n+\tfor (i = 0; i < s->n_extobjs; i++) {\n+\t\tstruct extobj_spec *extobj_spec = &s->extobjs[i];\n+\n+\t\tstatus = rte_swx_pipeline_extern_object_config(p,\n+\t\t\textobj_spec->name,\n+\t\t\textobj_spec->extern_type_name,\n+\t\t\textobj_spec->pragma);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Extern object configuration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\t/* regarray. */\n+\tfor (i = 0; i < s->n_regarrays; i++) {\n+\t\tstruct regarray_spec *regarray_spec = &s->regarrays[i];\n+\n+\t\tstatus = rte_swx_pipeline_regarray_config(p,\n+\t\t\tregarray_spec->name,\n+\t\t\tregarray_spec->size,\n+\t\t\tregarray_spec->init_val);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Register array configuration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\t/* metarray. */\n+\tfor (i = 0; i < s->n_metarrays; i++) {\n+\t\tstruct metarray_spec *metarray_spec = &s->metarrays[i];\n+\n+\t\tstatus = rte_swx_pipeline_metarray_config(p,\n+\t\t\tmetarray_spec->name,\n+\t\t\tmetarray_spec->size);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Meter array configuration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\t/* struct. */\n+\tfor (i = 0; i < s->n_structs; i++) {\n+\t\tstruct struct_spec *struct_spec = &s->structs[i];\n+\n+\t\tstatus = rte_swx_pipeline_struct_type_register(p,\n+\t\t\tstruct_spec->name,\n+\t\t\tstruct_spec->fields,\n+\t\t\tstruct_spec->n_fields,\n+\t\t\tstruct_spec->varbit);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Struct type registration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\t/* header. */\n+\tfor (i = 0; i < s->n_headers; i++) {\n+\t\tstruct header_spec *header_spec = &s->headers[i];\n+\n+\t\tstatus = rte_swx_pipeline_packet_header_register(p,\n+\t\t\theader_spec->name,\n+\t\t\theader_spec->struct_type_name);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Header configuration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\t/* metadata. */\n+\tfor (i = 0; i < s->n_metadata; i++) {\n+\t\tstruct metadata_spec *metadata_spec = &s->metadata[i];\n+\n+\t\tstatus = rte_swx_pipeline_packet_metadata_register(p,\n+\t\t\tmetadata_spec->struct_type_name);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Meta-data registration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\t/* action. */\n+\tfor (i = 0; i < s->n_actions; i++) {\n+\t\tstruct action_spec *action_spec = &s->actions[i];\n+\n+\t\tstatus = rte_swx_pipeline_action_config(p,\n+\t\t\taction_spec->name,\n+\t\t\taction_spec->args_struct_type_name,\n+\t\t\taction_spec->instructions,\n+\t\t\taction_spec->n_instructions);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Action configuration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\t/* table. */\n+\tfor (i = 0; i < s->n_tables; i++) {\n+\t\tstruct table_spec *table_spec = &s->tables[i];\n+\n+\t\tstatus = rte_swx_pipeline_table_config(p,\n+\t\t\ttable_spec->name,\n+\t\t\t&table_spec->params,\n+\t\t\ttable_spec->recommended_table_type_name,\n+\t\t\ttable_spec->args,\n+\t\t\ttable_spec->size);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Table configuration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\t/* selector. */\n+\tfor (i = 0; i < s->n_selectors; i++) {\n+\t\tstruct selector_spec *selector_spec = &s->selectors[i];\n+\n+\t\tstatus = rte_swx_pipeline_selector_config(p,\n+\t\t\tselector_spec->name,\n+\t\t\t&selector_spec->params);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Selector table configuration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\t/* learner. */\n+\tfor (i = 0; i < s->n_learners; i++) {\n+\t\tstruct learner_spec *learner_spec = &s->learners[i];\n+\n+\t\tstatus = rte_swx_pipeline_learner_config(p,\n+\t\t\tlearner_spec->name,\n+\t\t\t&learner_spec->params,\n+\t\t\tlearner_spec->size,\n+\t\t\tlearner_spec->timeout,\n+\t\t\tlearner_spec->n_timeouts);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Learner table configuration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\t/* apply. */\n+\tfor (i = 0; i < s->n_apply; i++) {\n+\t\tstruct apply_spec *apply_spec = &s->apply[i];\n+\n+\t\tstatus = rte_swx_pipeline_instructions_config(p,\n+\t\t\tapply_spec->instructions,\n+\t\t\tapply_spec->n_instructions);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Pipeline instructions configuration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n+\t\t\t\t FILE *spec_file,\n+\t\t\t\t uint32_t *err_line,\n+\t\t\t\t const char **err_msg)\n+{\n+\tstruct pipeline_spec *s = NULL;\n+\tint status = 0;\n+\n+\t/* Check the input arguments. */\n+\tif (!p || !spec_file) {\n+\t\tif (err_line)\n+\t\t\t*err_line = 0;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Invalid input argument.\";\n+\t\tstatus = -EINVAL;\n+\t\tgoto error;\n+\t}\n+\n+\t/* Spec file parse. */\n+\ts = pipeline_spec_parse(spec_file, err_line, err_msg);\n+\tif (!s) {\n+\t\tstatus = -EINVAL;\n+\t\tgoto error;\n+\t}\n+\n+\t/* Pipeline configure. */\n+\tstatus = pipeline_spec_configure(p, s, err_msg);\n+\tif (status) {\n+\t\tif (err_line)\n+\t\t\t*err_line = 0;\n+\t\tgoto error;\n+\t}\n+\n+\t/* Pipeline build. */\n+\tstatus = rte_swx_pipeline_build(p);\n+\tif (status) {\n+\t\tif (err_line)\n+\t\t\t*err_line = 0;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Pipeline build error.\";\n+\t\tgoto error;\n+\t}\n+\n+\treturn 0;\n+\n+error:\n+\tpipeline_spec_free(s);\n \treturn status;\n }\ndiff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h\nindex e1170a33b1..4f3a0b5958 100644\n--- a/lib/pipeline/rte_swx_pipeline_spec.h\n+++ b/lib/pipeline/rte_swx_pipeline_spec.h\n@@ -206,3 +206,12 @@ struct pipeline_spec {\n \n void\n pipeline_spec_free(struct pipeline_spec *s);\n+struct pipeline_spec *\n+pipeline_spec_parse(FILE *spec,\n+\t\t    uint32_t *err_line,\n+\t\t    const char **err_msg);\n+\n+int\n+pipeline_spec_configure(struct rte_swx_pipeline *p,\n+\t\t\tstruct pipeline_spec *s,\n+\t\t\tconst char **err_msg);\n",
    "prefixes": [
        "V6",
        "04/17"
    ]
}