get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 114284,
    "url": "http://patches.dpdk.org/api/patches/114284/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20220727223639.598932-6-cristian.dumitrescu@intel.com/",
    "project": {
        "id": 1,
        "url": "http://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": "<20220727223639.598932-6-cristian.dumitrescu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20220727223639.598932-6-cristian.dumitrescu@intel.com",
    "date": "2022-07-27T22:36:28",
    "name": "[V3,06/17] pipeline: add support for pipeline I/O specification",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "3944850e578e2e27ac4c3d891ae3a1c2a7f56e2f",
    "submitter": {
        "id": 19,
        "url": "http://patches.dpdk.org/api/people/19/?format=api",
        "name": "Cristian Dumitrescu",
        "email": "cristian.dumitrescu@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20220727223639.598932-6-cristian.dumitrescu@intel.com/mbox/",
    "series": [
        {
            "id": 24106,
            "url": "http://patches.dpdk.org/api/series/24106/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=24106",
            "date": "2022-07-27T22:36:23",
            "name": "[V3,01/17] pipeline: add pipeline name",
            "version": 3,
            "mbox": "http://patches.dpdk.org/series/24106/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/114284/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/114284/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 4F3DEA00C4;\n\tThu, 28 Jul 2022 00:37:16 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 73A6C42B85;\n\tThu, 28 Jul 2022 00:36:51 +0200 (CEST)",
            "from mga06.intel.com (mga06b.intel.com [134.134.136.31])\n by mails.dpdk.org (Postfix) with ESMTP id B10AC42826\n for <dev@dpdk.org>; Thu, 28 Jul 2022 00:36:46 +0200 (CEST)",
            "from orsmga008.jf.intel.com ([10.7.209.65])\n by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 27 Jul 2022 15:36:46 -0700",
            "from silpixa00400573.ir.intel.com (HELO\n silpixa00400573.ger.corp.intel.com.) ([10.237.223.157])\n by orsmga008.jf.intel.com with ESMTP; 27 Jul 2022 15:36:45 -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=1658961406; x=1690497406;\n h=from:to:cc:subject:date:message-id:in-reply-to:\n references:mime-version:content-transfer-encoding;\n bh=d8osSXcqaKWWR9YiLtw8k8acRw6ZQ8TqIq5Oy4a5ulc=;\n b=AfGWCg96eIZOSG3+iCfw/t0JEEQP7xevgJb6hKcjvEVxcU5o20mae8zS\n zz/EdzmXqp2yIKdglNty3RqFSVT6zSwP2O0ssIKpeRsRugibex9vpX/Z8\n 9jtQXDOSOxFJlfSsJ4ycB1Dkwixlr4y5fj8QC293u/kwaszmbDq+MpGJu\n D0HIaelc3XWSIft+XZeU0bF7my7qLvbMICH1k7U+QP27HGxCbcqWgB4sd\n unRycbgdj2G2fsj9xJ6QWJEfC0SJ5XO0V9CmFUYAxWU0ZKsIZYBSMWloq\n E3cdrRAJLsmLL8tZRuWJdugfARrpYThCWer5ThHMOTRW0I8d1TjJVJGCQ w==;",
        "X-IronPort-AV": [
            "E=McAfee;i=\"6400,9594,10421\"; a=\"350068826\"",
            "E=Sophos;i=\"5.93,196,1654585200\"; d=\"scan'208\";a=\"350068826\"",
            "E=Sophos;i=\"5.93,196,1654585200\"; d=\"scan'208\";a=\"628567626\""
        ],
        "X-ExtLoop1": "1",
        "From": "Cristian Dumitrescu <cristian.dumitrescu@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "\"Kamalakannan R .\" <kamalakannan.r@intel.com>",
        "Subject": "[PATCH V3 06/17] pipeline: add support for pipeline I/O specification",
        "Date": "Wed, 27 Jul 2022 22:36:28 +0000",
        "Message-Id": "<20220727223639.598932-6-cristian.dumitrescu@intel.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20220727223639.598932-1-cristian.dumitrescu@intel.com>",
        "References": "<20220718132603.339314-1-cristian.dumitrescu@intel.com>\n <20220727223639.598932-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": "Add specification data structure and API for the pipeline I/O ports\nand related pipeline configuration such as packet mirroring.\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 | 852 +++++++++++++++++++++++++++\n lib/pipeline/rte_swx_pipeline_spec.h |  58 ++\n 2 files changed, 910 insertions(+)",
    "diff": "diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c\nindex bf21fe17ba..89cf194b19 100644\n--- a/lib/pipeline/rte_swx_pipeline_spec.c\n+++ b/lib/pipeline/rte_swx_pipeline_spec.c\n@@ -9,6 +9,12 @@\n #include <errno.h>\n \n #include <rte_common.h>\n+#include <rte_mempool.h>\n+\n+#include <rte_swx_port_ethdev.h>\n+#include <rte_swx_port_ring.h>\n+#include <rte_swx_port_source_sink.h>\n+#include <rte_swx_port_fd.h>\n \n #include \"rte_swx_pipeline_spec.h\"\n \n@@ -3566,3 +3572,849 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p,\n \tpipeline_spec_free(s);\n \treturn status;\n }\n+\n+static void\n+port_in_params_free(void *params, const char *port_type)\n+{\n+\tuintptr_t dev_name;\n+\n+\tif (!params || !port_type)\n+\t\treturn;\n+\n+\tif (!strcmp(port_type, \"ethdev\")) {\n+\t\tstruct rte_swx_port_ethdev_reader_params *p = params;\n+\n+\t\tdev_name = (uintptr_t)p->dev_name;\n+\t} else if (!strcmp(port_type, \"ring\")) {\n+\t\tstruct rte_swx_port_ring_reader_params *p = params;\n+\n+\t\tdev_name = (uintptr_t)p->name;\n+\t} else if (!strcmp(port_type, \"source\")) {\n+\t\tstruct rte_swx_port_source_params *p = params;\n+\n+\t\tdev_name = (uintptr_t)p->file_name;\n+\t} else\n+\t\tdev_name = (uintptr_t)NULL;\n+\n+\tfree((void *)dev_name);\n+\tfree(params);\n+}\n+\n+static void\n+port_out_params_free(void *params, const char *port_type)\n+{\n+\tuintptr_t dev_name;\n+\n+\tif (!params || !port_type)\n+\t\treturn;\n+\n+\tif (!strcmp(port_type, \"ethdev\")) {\n+\t\tstruct rte_swx_port_ethdev_writer_params *p = params;\n+\n+\t\tdev_name = (uintptr_t)p->dev_name;\n+\t} else if (!strcmp(port_type, \"ring\")) {\n+\t\tstruct rte_swx_port_ring_writer_params *p = params;\n+\n+\t\tdev_name = (uintptr_t)p->name;\n+\t} else if (!strcmp(port_type, \"sink\")) {\n+\t\tstruct rte_swx_port_sink_params *p = params;\n+\n+\t\tdev_name = (uintptr_t)p->file_name;\n+\t} else\n+\t\tdev_name = (uintptr_t)NULL;\n+\n+\tfree((void *)dev_name);\n+\tfree(params);\n+}\n+\n+void\n+pipeline_iospec_free(struct pipeline_iospec *s)\n+{\n+\tuint32_t i;\n+\n+\tif (!s)\n+\t\treturn;\n+\n+\t/* Input ports. */\n+\tfor (i = 0; i < s->n_ports_in; i++) {\n+\t\tuintptr_t name = (uintptr_t)s->port_in_type[i];\n+\n+\t\tport_in_params_free(s->port_in_params[i], s->port_in_type[i]);\n+\t\tfree((void *)name);\n+\t}\n+\n+\tfree(s->port_in_type);\n+\tfree(s->port_in_params);\n+\n+\t/* Output ports. */\n+\tfor (i = 0; i < s->n_ports_out; i++) {\n+\t\tuintptr_t name = (uintptr_t)s->port_out_type[i];\n+\n+\t\tport_out_params_free(s->port_out_params[i], s->port_out_type[i]);\n+\t\tfree((void *)name);\n+\t}\n+\n+\tfree(s->port_out_type);\n+\tfree(s->port_out_params);\n+\n+\tfree(s);\n+}\n+\n+static int\n+mirroring_parse(struct rte_swx_pipeline_mirroring_params *p,\n+\t\tchar **tokens,\n+\t\tuint32_t n_tokens,\n+\t\tconst char **err_msg)\n+{\n+\tchar *token;\n+\n+\tif ((n_tokens != 4) || strcmp(tokens[0], \"slots\") || strcmp(tokens[2], \"sessions\")) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid statement.\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* <n_slots>. */\n+\ttoken = tokens[1];\n+\tp->n_slots = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <n_slots> parameter.\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* <n_sessions>. */\n+\ttoken = tokens[3];\n+\tp->n_sessions = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <n_sessions> parameter.\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void *\n+port_in_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)\n+{\n+\tstruct rte_swx_port_ethdev_reader_params *p = NULL;\n+\tchar *token, *dev_name = NULL;\n+\tuint32_t queue_id, burst_size;\n+\n+\tif ((n_tokens != 5) || strcmp(tokens[1], \"rxq\") || strcmp(tokens[3], \"bsz\")) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid statement.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <queue_id>. */\n+\ttoken = tokens[2];\n+\tqueue_id = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <queue_id> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <burst_size>. */\n+\ttoken = tokens[4];\n+\tburst_size = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <burst_size> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Memory allocation. */\n+\tdev_name = strdup(tokens[0]);\n+\tp = malloc(sizeof(struct rte_swx_port_ethdev_reader_params));\n+\tif (!dev_name || !p) {\n+\t\tfree(dev_name);\n+\t\tfree(p);\n+\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Memory allocation failed.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Initialization. */\n+\tp->dev_name = dev_name;\n+\tp->queue_id = queue_id;\n+\tp->burst_size = burst_size;\n+\n+\treturn p;\n+}\n+\n+static void *\n+port_in_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)\n+{\n+\tstruct rte_swx_port_ring_reader_params *p = NULL;\n+\tchar *token, *name = NULL;\n+\tuint32_t burst_size;\n+\n+\tif ((n_tokens != 3) || strcmp(tokens[1], \"bsz\")) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid statement.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <burst_size>. */\n+\ttoken = tokens[2];\n+\tburst_size = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <burst_size> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Memory allocation. */\n+\tname = strdup(tokens[0]);\n+\tp = malloc(sizeof(struct rte_swx_port_ring_reader_params));\n+\tif (!name || !p) {\n+\t\tfree(name);\n+\t\tfree(p);\n+\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Memory allocation failed.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Initialization. */\n+\tp->name = name;\n+\tp->burst_size = burst_size;\n+\n+\treturn p;\n+}\n+\n+static void *\n+port_in_source_parse(char **tokens, uint32_t n_tokens, const char **err_msg)\n+{\n+\tstruct rte_swx_port_source_params *p = NULL;\n+\tstruct rte_mempool *pool = NULL;\n+\tchar *token, *file_name = NULL;\n+\tuint32_t n_loops, n_pkts_max;\n+\n+\tif ((n_tokens != 8) ||\n+\t    strcmp(tokens[0], \"mempool\") ||\n+\t    strcmp(tokens[2], \"file\") ||\n+\t    strcmp(tokens[4], \"loop\") ||\n+\t    strcmp(tokens[6], \"packets\")) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid statement.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <mempool_name>. */\n+\tpool = rte_mempool_lookup(tokens[1]);\n+\tif (!pool) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <mempool_name> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <n_loops>. */\n+\ttoken = tokens[5];\n+\tn_loops = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <n_loops> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <n_pkts_max>. */\n+\ttoken = tokens[7];\n+\tn_pkts_max = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <n_pkts_max> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Memory allocation. */\n+\tfile_name = strdup(tokens[3]);\n+\tp = malloc(sizeof(struct rte_swx_port_source_params));\n+\tif (!file_name || !p) {\n+\t\tfree(file_name);\n+\t\tfree(p);\n+\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Memory allocation failed.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Initialization. */\n+\tp->pool = pool;\n+\tp->file_name = file_name;\n+\tp->n_loops = n_loops;\n+\tp->n_pkts_max = n_pkts_max;\n+\n+\treturn p;\n+}\n+\n+static void *\n+port_in_fd_parse(char **tokens,\n+\t\t uint32_t n_tokens,\n+\t\t const char **err_msg)\n+{\n+\tstruct rte_swx_port_fd_reader_params *p = NULL;\n+\tstruct rte_mempool *mempool = NULL;\n+\tchar *token;\n+\tuint32_t mtu, burst_size;\n+\tint fd;\n+\n+\tif ((n_tokens != 7) ||\n+\t    strcmp(tokens[1], \"mtu\") ||\n+\t    strcmp(tokens[3], \"mempool\") ||\n+\t    strcmp(tokens[5], \"bsz\")) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid statement.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <file_descriptor>. */\n+\ttoken = tokens[0];\n+\tfd = strtol(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <file_descriptor> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <mtu>. */\n+\ttoken = tokens[2];\n+\tmtu = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <mtu> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <mempool_name>. */\n+\tmempool = rte_mempool_lookup(tokens[4]);\n+\tif (!mempool) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <mempool_name> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <burst_size>. */\n+\ttoken = tokens[6];\n+\tburst_size = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <burst_size> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Memory allocation. */\n+\tp = malloc(sizeof(struct rte_swx_port_fd_reader_params));\n+\tif (!p) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Memory allocation failed.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Initialization. */\n+\tp->fd = fd;\n+\tp->mtu = mtu;\n+\tp->mempool = mempool;\n+\tp->burst_size = burst_size;\n+\n+\treturn p;\n+}\n+\n+static void *\n+port_out_ethdev_parse(char **tokens, uint32_t n_tokens, const char **err_msg)\n+{\n+\tstruct rte_swx_port_ethdev_writer_params *p = NULL;\n+\tchar *token, *dev_name = NULL;\n+\tuint32_t queue_id, burst_size;\n+\n+\tif ((n_tokens != 5) || strcmp(tokens[1], \"txq\") || strcmp(tokens[3], \"bsz\")) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid statement.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <queue_id>. */\n+\ttoken = tokens[2];\n+\tqueue_id = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <queue_id> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <burst_size>. */\n+\ttoken = tokens[4];\n+\tburst_size = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <burst_size> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Memory allocation. */\n+\tdev_name = strdup(tokens[0]);\n+\tp = malloc(sizeof(struct rte_swx_port_ethdev_writer_params));\n+\tif (!dev_name || !p) {\n+\t\tfree(dev_name);\n+\t\tfree(p);\n+\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Memory allocation failed.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Initialization. */\n+\tp->dev_name = dev_name;\n+\tp->queue_id = queue_id;\n+\tp->burst_size = burst_size;\n+\n+\treturn p;\n+}\n+\n+static void *\n+port_out_ring_parse(char **tokens, uint32_t n_tokens, const char **err_msg)\n+{\n+\tstruct rte_swx_port_ring_writer_params *p = NULL;\n+\tchar *token, *name = NULL;\n+\tuint32_t burst_size;\n+\n+\tif ((n_tokens != 3) || strcmp(tokens[1], \"bsz\")) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid statement.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <burst_size>. */\n+\ttoken = tokens[2];\n+\tburst_size = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <burst_size> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Memory allocation. */\n+\tname = strdup(tokens[0]);\n+\tp = malloc(sizeof(struct rte_swx_port_ring_writer_params));\n+\tif (!name || !p) {\n+\t\tfree(name);\n+\t\tfree(p);\n+\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Memory allocation failed.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Initialization. */\n+\tp->name = name;\n+\tp->burst_size = burst_size;\n+\n+\treturn p;\n+}\n+\n+static void *\n+port_out_sink_parse(char **tokens, uint32_t n_tokens, const char **err_msg)\n+{\n+\tstruct rte_swx_port_sink_params *p = NULL;\n+\tchar *file_name = NULL;\n+\tint file_name_valid = 0;\n+\n+\tif ((n_tokens != 2) || strcmp(tokens[0], \"file\")){\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid statement.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Memory allocation. */\n+\tif (strcmp(tokens[1], \"none\")) {\n+\t\tfile_name_valid = 1;\n+\t\tfile_name = strdup(tokens[1]);\n+\t}\n+\n+\tp = malloc(sizeof(struct rte_swx_port_ring_writer_params));\n+\tif ((file_name_valid && !file_name) || !p) {\n+\t\tfree(file_name);\n+\t\tfree(p);\n+\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Memory allocation failed.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Initialization. */\n+\tp->file_name = file_name;\n+\n+\treturn p;\n+}\n+\n+static void *\n+port_out_fd_parse(char **tokens,\n+\t\t  uint32_t n_tokens,\n+\t\t  const char **err_msg)\n+{\n+\tstruct rte_swx_port_fd_writer_params *p = NULL;\n+\tchar *token;\n+\tuint32_t burst_size;\n+\tint fd;\n+\n+\tif ((n_tokens != 3) || strcmp(tokens[1], \"bsz\")) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid statement.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <file_descriptor>. */\n+\ttoken = tokens[0];\n+\tfd = strtol(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <file_descriptor> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* <burst_size>. */\n+\ttoken = tokens[2];\n+\tburst_size = strtoul(token, &token, 0);\n+\tif (token[0]) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Invalid <burst_size> parameter.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Memory allocation. */\n+\tp = malloc(sizeof(struct rte_swx_port_fd_writer_params));\n+\tif (!p) {\n+\t\tif (err_msg)\n+\t\t    *err_msg = \"Memory allocation failed.\";\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Initialization. */\n+\tp->fd = fd;\n+\tp->burst_size = burst_size;\n+\n+\treturn p;\n+}\n+\n+struct pipeline_iospec *\n+pipeline_iospec_parse(FILE *spec,\n+\t\t      uint32_t *err_line,\n+\t\t      const char **err_msg)\n+{\n+\tstruct pipeline_iospec *s = NULL;\n+\tuint32_t n_lines = 0;\n+\n+\t/* Check the input arguments. */\n+\tif (!spec) {\n+\t\tif (err_line)\n+\t\t\t*err_line = n_lines;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Invalid input argument.\";\n+\t\tgoto error;\n+\t}\n+\n+\t/* Memory allocation. */\n+\ts = calloc(sizeof(struct pipeline_iospec), 1);\n+\tif (!s) {\n+\t\tif (err_line)\n+\t\t\t*err_line = n_lines;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Memory allocation failed.\";\n+\t\tgoto error;\n+\t}\n+\n+\t/* Initialize with the defaut values. */\n+\ts->mirroring_params.n_slots = RTE_SWX_PACKET_MIRRORING_SLOTS_DEFAULT;\n+\ts->mirroring_params.n_sessions = RTE_SWX_PACKET_MIRRORING_SESSIONS_DEFAULT;\n+\n+\tfor (n_lines = 1; ; n_lines++) {\n+\t\tchar line[MAX_LINE_LENGTH];\n+\t\tchar *tokens[MAX_TOKENS], *ptr = line;\n+\t\tuint32_t n_tokens = 0;\n+\n+\t\t/* Read next line. */\n+\t\tif (!fgets(line, sizeof(line), spec))\n+\t\t\tbreak;\n+\n+\t\t/* Parse the line into tokens. */\n+\t\tfor ( ; ; ) {\n+\t\t\tchar *token;\n+\n+\t\t\t/* Get token. */\n+\t\t\ttoken = strtok_r(ptr, \" \\f\\n\\r\\t\\v\", &ptr);\n+\t\t\tif (!token)\n+\t\t\t\tbreak;\n+\n+\t\t\t/* Handle comments. */\n+\t\t\tif ((token[0] == '#') ||\n+\t\t\t    (token[0] == ';') ||\n+\t\t\t    ((token[0] == '/') && (token[1] == '/'))) {\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\t/* Handle excessively long lines. */\n+\t\t\tif (n_tokens >= RTE_DIM(tokens)) {\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 = \"Too many tokens.\";\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t\t/* Handle excessively long tokens. */\n+\t\t\tif (strnlen(token, RTE_SWX_NAME_SIZE) >=\n+\t\t\t    RTE_SWX_NAME_SIZE) {\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 = \"Token too big.\";\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t\t/* Save token. */\n+\t\t\ttokens[n_tokens] = token;\n+\t\t\tn_tokens++;\n+\t\t}\n+\n+\t\t/* Handle empty lines. */\n+\t\tif (!n_tokens)\n+\t\t\tcontinue;\n+\n+\t\t/* mirroring. */\n+\t\tif ((n_tokens >= 1) && !strcmp(tokens[0], \"mirroring\")) {\n+\t\t\tint status = 0;\n+\n+\t\t\tstatus = mirroring_parse(&s->mirroring_params,\n+\t\t\t\t\t\t &tokens[1],\n+\t\t\t\t\t\t n_tokens - 1,\n+\t\t\t\t\t\t err_msg);\n+\t\t\tif (status) {\n+\t\t\t\tif (err_line)\n+\t\t\t\t\t*err_line = n_lines;\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* port in. */\n+\t\tif ((n_tokens >= 4) && !strcmp(tokens[0], \"port\") && !strcmp(tokens[1], \"in\")) {\n+\t\t\tchar *token = tokens[2];\n+\t\t\tuint32_t *new_id = NULL;\n+\t\t\tconst char **new_type = NULL, *port_type = NULL;\n+\t\t\tvoid **new_params = NULL, *p = NULL;\n+\t\t\tuint32_t port_id;\n+\n+\t\t\t/* <port_id>. */\n+\t\t\tport_id = strtoul(token, &token, 0);\n+\t\t\tif (token[0]) {\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 = \"Invalid port ID.\";\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t\t/* <port_type>. */\n+\t\t\tif (!strcmp(tokens[3], \"ethdev\"))\n+\t\t\t\tp = port_in_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);\n+\t\t\telse if (!strcmp(tokens[3], \"ring\"))\n+\t\t\t\tp = port_in_ring_parse(&tokens[4], n_tokens - 4, err_msg);\n+\t\t\telse if (!strcmp(tokens[3], \"source\"))\n+\t\t\t\tp = port_in_source_parse(&tokens[4], n_tokens - 4, err_msg);\n+\t\t\telse if (!strcmp(tokens[3], \"fd\"))\n+\t\t\t\tp = port_in_fd_parse(&tokens[4], n_tokens - 4, err_msg);\n+\t\t\telse {\n+\t\t\t\tp = NULL;\n+\t\t\t\tif (err_msg)\n+\t\t\t\t\t*err_msg = \"Invalid port type.\";\n+\t\t\t}\n+\n+\t\t\tif (!p) {\n+\t\t\t\tif (err_line)\n+\t\t\t\t\t*err_line = n_lines;\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t\t/* New port. */\n+\t\t\tport_type = strdup(tokens[3]);\n+\t\t\tnew_id = realloc(s->port_in_id,\n+\t\t\t\t\t (s->n_ports_in + 1) * sizeof(uint32_t));\n+\t\t\tnew_type = realloc(s->port_in_type,\n+\t\t\t\t\t   (s->n_ports_in + 1) * sizeof(char *));\n+\t\t\tnew_params = realloc(s->port_in_params,\n+\t\t\t\t\t     (s->n_ports_in + 1) * sizeof(void *));\n+\t\t\tif (!port_type || !new_id || !new_type || !new_params) {\n+\t\t\t\tuintptr_t pt = (uintptr_t)port_type;\n+\n+\t\t\t\tport_in_params_free(p, tokens[3]);\n+\t\t\t\tfree((void *)pt);\n+\t\t\t\tfree(new_id);\n+\t\t\t\tfree(new_type);\n+\t\t\t\tfree(new_params);\n+\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 = \"Memory allocation failed.\";\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t\ts->port_in_id = new_id;\n+\t\t\ts->port_in_type = new_type;\n+\t\t\ts->port_in_params = new_params;\n+\n+\t\t\ts->port_in_id[s->n_ports_in] = port_id;\n+\t\t\ts->port_in_type[s->n_ports_in] = port_type;\n+\t\t\ts->port_in_params[s->n_ports_in] = p;\n+\t\t\ts->n_ports_in++;\n+\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* port out. */\n+\t\tif ((n_tokens >= 4) && !strcmp(tokens[0], \"port\") && !strcmp(tokens[1], \"out\")) {\n+\t\t\tchar *token = tokens[2];\n+\t\t\tuint32_t *new_id = NULL;\n+\t\t\tconst char **new_type = NULL, *port_type = NULL;\n+\t\t\tvoid **new_params = NULL, *p = NULL;\n+\t\t\tuint32_t port_id;\n+\n+\t\t\t/* <port_id>. */\n+\t\t\tport_id = strtoul(token, &token, 0);\n+\t\t\tif (token[0]) {\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 = \"Invalid port ID.\";\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t\t/* <port_type>. */\n+\t\t\tif (!strcmp(tokens[3], \"ethdev\"))\n+\t\t\t\tp = port_out_ethdev_parse(&tokens[4], n_tokens - 4, err_msg);\n+\t\t\telse if (!strcmp(tokens[3], \"ring\"))\n+\t\t\t\tp = port_out_ring_parse(&tokens[4], n_tokens - 4, err_msg);\n+\t\t\telse if (!strcmp(tokens[3], \"sink\"))\n+\t\t\t\tp = port_out_sink_parse(&tokens[4], n_tokens - 4, err_msg);\n+\t\t\telse if (!strcmp(tokens[3], \"fd\"))\n+\t\t\t\tp = port_out_fd_parse(&tokens[4], n_tokens - 4, err_msg);\n+\t\t\telse {\n+\t\t\t\tp = NULL;\n+\t\t\t\tif (err_msg)\n+\t\t\t\t\t*err_msg = \"Invalid port type.\";\n+\t\t\t}\n+\n+\t\t\tif (!p) {\n+\t\t\t\tif (err_line)\n+\t\t\t\t\t*err_line = n_lines;\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t\t/* New port. */\n+\t\t\tport_type = strdup(tokens[3]);\n+\t\t\tnew_id = realloc(s->port_out_id,\n+\t\t\t\t\t (s->n_ports_out + 1) * sizeof(uint32_t));\n+\t\t\tnew_type = realloc(s->port_out_type,\n+\t\t\t\t\t   (s->n_ports_out + 1) * sizeof(char *));\n+\t\t\tnew_params = realloc(s->port_out_params,\n+\t\t\t\t\t     (s->n_ports_out + 1) * sizeof(void *));\n+\t\t\tif (!port_type || !new_id || !new_type || !new_params) {\n+\t\t\t\tuintptr_t pt = (uintptr_t)port_type;\n+\n+\t\t\t\tport_out_params_free(p, tokens[3]);\n+\t\t\t\tfree((void *)pt);\n+\t\t\t\tfree(new_id);\n+\t\t\t\tfree(new_type);\n+\t\t\t\tfree(new_params);\n+\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 = \"Memory allocation failed.\";\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t\ts->port_out_id = new_id;\n+\t\t\ts->port_out_type = new_type;\n+\t\t\ts->port_out_params = new_params;\n+\n+\t\t\ts->port_out_id[s->n_ports_out] = port_id;\n+\t\t\ts->port_out_type[s->n_ports_out] = port_type;\n+\t\t\ts->port_out_params[s->n_ports_out] = p;\n+\t\t\ts->n_ports_out++;\n+\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* Anything else. */\n+\t\tif (err_line)\n+\t\t\t*err_line = n_lines;\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Unknown I/O statement.\";\n+\t\tgoto error;\n+\t}\n+\n+\treturn s;\n+\n+error:\n+\tpipeline_iospec_free(s);\n+\n+\treturn NULL;\n+}\n+\n+int\n+pipeline_iospec_configure(struct rte_swx_pipeline *p,\n+\t\t\t  struct pipeline_iospec *s,\n+\t\t\t  const char **err_msg)\n+{\n+\tuint32_t i;\n+\tint status = 0;\n+\n+\t/* Check input arguments. */\n+\tif (!p || !s) {\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Invalid input argument\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Mirroring. */\n+\tstatus = rte_swx_pipeline_mirroring_config(p, &s->mirroring_params);\n+\tif (status) {\n+\t\tif (err_msg)\n+\t\t\t*err_msg = \"Pipeline mirroring configuration error.\";\n+\t\treturn status;\n+\t}\n+\n+\t/* Input ports. */\n+\tfor (i = 0; i < s->n_ports_in; i++) {\n+\t\tstatus = rte_swx_pipeline_port_in_config(p,\n+\t\t\t\t\t\t\t i,\n+\t\t\t\t\t\t\t s->port_in_type[i],\n+\t\t\t\t\t\t\t s->port_in_params[i]);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Pipeline input port configuration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\t/* Output ports. */\n+\tfor (i = 0; i < s->n_ports_out; i++) {\n+\t\tstatus = rte_swx_pipeline_port_out_config(p,\n+\t\t\t\t\t\t\t  i,\n+\t\t\t\t\t\t\t  s->port_out_type[i],\n+\t\t\t\t\t\t\t  s->port_out_params[i]);\n+\t\tif (status) {\n+\t\t\tif (err_msg)\n+\t\t\t\t*err_msg = \"Pipeline output port configuration error.\";\n+\t\t\treturn status;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/lib/pipeline/rte_swx_pipeline_spec.h b/lib/pipeline/rte_swx_pipeline_spec.h\nindex 707b99ba09..62ac4ecfc4 100644\n--- a/lib/pipeline/rte_swx_pipeline_spec.h\n+++ b/lib/pipeline/rte_swx_pipeline_spec.h\n@@ -1,6 +1,13 @@\n /* SPDX-License-Identifier: BSD-3-Clause\n  * Copyright(c) 2022 Intel Corporation\n  */\n+#ifndef __INCLUDE_RTE_SWX_PIPELINE_SPEC_H__\n+#define __INCLUDE_RTE_SWX_PIPELINE_SPEC_H__\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n #include <stdint.h>\n #include <stdio.h>\n \n@@ -204,6 +211,38 @@ struct pipeline_spec {\n \tuint32_t n_apply;\n };\n \n+/*\n+ * Mirroring:\n+ *      mirroring slots <n_slots> sessions <n_sessions>\n+ *\n+ * Input ports:\n+ *      port in <port_id> ethdev <ethdev_name> rxq <queue_id> bsz <burst_size>\n+ *      port in <port_id> ring <ring_name> bsz <burst_size>\n+ *      port in <port_id> source mempool <mempool_name> file <file_name> loop <n_loops>\n+ *                               packets <n_pkts_max>\n+ *      port in <port_id> fd <file_descriptor> mtu <mtu> mempool <mempool_name> bsz <burst_size>\n+ *\n+ * Output ports:\n+ *      port out <port_id> ethdev <ethdev_name> txq <queue_id> bsz <burst_size>\n+ *      port out <port_id> ring <ring_name> bsz <burst_size>\n+ *      port out <port_id> sink file <file_name> | none\n+ *      port out <port_id> fd <file_descriptor> bsz <burst_size>\n+ */\n+struct pipeline_iospec {\n+\tstruct rte_swx_pipeline_mirroring_params mirroring_params;\n+\n+\tuint32_t *port_in_id;\n+\tconst char **port_in_type;\n+\tvoid **port_in_params;\n+\n+\tuint32_t *port_out_id;\n+\tconst char **port_out_type;\n+\tvoid **port_out_params;\n+\n+\tuint32_t n_ports_in;\n+\tuint32_t n_ports_out;\n+};\n+\n void\n pipeline_spec_free(struct pipeline_spec *s);\n \n@@ -220,3 +259,22 @@ 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+void\n+pipeline_iospec_free(struct pipeline_iospec *s);\n+\n+struct pipeline_iospec *\n+pipeline_iospec_parse(FILE *spec,\n+\t\t      uint32_t *err_line,\n+\t\t      const char **err_msg);\n+\n+int\n+pipeline_iospec_configure(struct rte_swx_pipeline *p,\n+\t\t\t  struct pipeline_iospec *s,\n+\t\t\t  const char **err_msg);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif\n",
    "prefixes": [
        "V3",
        "06/17"
    ]
}