get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 7334,
    "url": "https://patches.dpdk.org/api/patches/7334/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1443635148-31533-1-git-send-email-jasvinder.singh@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": "<1443635148-31533-1-git-send-email-jasvinder.singh@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1443635148-31533-1-git-send-email-jasvinder.singh@intel.com",
    "date": "2015-09-30T17:45:48",
    "name": "[dpdk-dev] ip_pipeline: add flow id parameter to flow classification",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "41bab33f1abeca347842032b20239e5122eca3f4",
    "submitter": {
        "id": 285,
        "url": "https://patches.dpdk.org/api/people/285/?format=api",
        "name": "Jasvinder Singh",
        "email": "jasvinder.singh@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1443635148-31533-1-git-send-email-jasvinder.singh@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/7334/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/7334/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id E40068DAA;\n\tWed, 30 Sep 2015 19:46:17 +0200 (CEST)",
            "from mga11.intel.com (mga11.intel.com [192.55.52.93])\n\tby dpdk.org (Postfix) with ESMTP id B2EDF8D90\n\tfor <dev@dpdk.org>; Wed, 30 Sep 2015 19:46:16 +0200 (CEST)",
            "from fmsmga002.fm.intel.com ([10.253.24.26])\n\tby fmsmga102.fm.intel.com with ESMTP; 30 Sep 2015 10:45:50 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby fmsmga002.fm.intel.com with ESMTP; 30 Sep 2015 10:45:49 -0700",
            "from sivswdev02.ir.intel.com (sivswdev02.ir.intel.com\n\t[10.237.217.46])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\tt8UHjmn8009995; Wed, 30 Sep 2015 18:45:48 +0100",
            "from sivswdev02.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev02.ir.intel.com with ESMTP id t8UHjmkI031570;\n\tWed, 30 Sep 2015 18:45:48 +0100",
            "(from jasvinde@localhost)\n\tby sivswdev02.ir.intel.com with  id t8UHjmeO031566;\n\tWed, 30 Sep 2015 18:45:48 +0100"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.17,613,1437462000\"; d=\"scan'208\";a=\"816416725\"",
        "From": "Jasvinder Singh <jasvinder.singh@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Wed, 30 Sep 2015 18:45:48 +0100",
        "Message-Id": "<1443635148-31533-1-git-send-email-jasvinder.singh@intel.com>",
        "X-Mailer": "git-send-email 1.7.4.1",
        "Subject": "[dpdk-dev] [PATCH] ip_pipeline: add flow id parameter to flow\n\tclassification",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This patch adds flow id field to the flow\nclassification table entries and adds table action\nhandlers to read flow id from table entry and\nwrite it into the packet meta-data. The flow_id\n(32-bit) parameter is also added to CLI commands\nflow add, flow delete, etc.\n\nSigned-off-by: Jasvinder Singh <jasvinder.singh@intel.com>\n---\n .../pipeline/pipeline_flow_classification.c        | 206 ++++++++++++++++++---\n .../pipeline/pipeline_flow_classification.h        |   4 +-\n .../pipeline/pipeline_flow_classification_be.c     | 114 +++++++++++-\n .../pipeline/pipeline_flow_classification_be.h     |   2 +\n 4 files changed, 295 insertions(+), 31 deletions(-)",
    "diff": "diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c\nindex 4b82180..04b6915 100644\n--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c\n+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c\n@@ -152,6 +152,7 @@ app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,\n struct app_pipeline_fc_flow {\n \tstruct pipeline_fc_key key;\n \tuint32_t port_id;\n+\tuint32_t flow_id;\n \tuint32_t signature;\n \tvoid *entry_ptr;\n \n@@ -280,7 +281,8 @@ int\n app_pipeline_fc_add(struct app_params *app,\n \tuint32_t pipeline_id,\n \tstruct pipeline_fc_key *key,\n-\tuint32_t port_id)\n+\tuint32_t port_id,\n+\tuint32_t flow_id)\n {\n \tstruct app_pipeline_fc *p;\n \tstruct app_pipeline_fc_flow *flow;\n@@ -325,6 +327,7 @@ app_pipeline_fc_add(struct app_params *app,\n \treq->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD;\n \tapp_pipeline_fc_key_convert(key, req->key, &signature);\n \treq->port_id = port_id;\n+\treq->flow_id = flow_id;\n \n \t/* Send request and wait for response */\n \trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);\n@@ -348,6 +351,7 @@ app_pipeline_fc_add(struct app_params *app,\n \tmemset(&flow->key, 0, sizeof(flow->key));\n \tmemcpy(&flow->key, key, sizeof(flow->key));\n \tflow->port_id = port_id;\n+\tflow->flow_id = flow_id;\n \tflow->signature = signature;\n \tflow->entry_ptr = rsp->entry_ptr;\n \n@@ -370,6 +374,7 @@ app_pipeline_fc_add_bulk(struct app_params *app,\n \tuint32_t pipeline_id,\n \tstruct pipeline_fc_key *key,\n \tuint32_t *port_id,\n+\tuint32_t *flow_id,\n \tuint32_t n_keys)\n {\n \tstruct app_pipeline_fc *p;\n@@ -389,6 +394,7 @@ app_pipeline_fc_add_bulk(struct app_params *app,\n \tif ((app == NULL) ||\n \t\t(key == NULL) ||\n \t\t(port_id == NULL) ||\n+\t\t(flow_id == NULL) ||\n \t\t(n_keys == 0))\n \t\treturn -1;\n \n@@ -496,6 +502,7 @@ app_pipeline_fc_add_bulk(struct app_params *app,\n \t\t\tflow_req[i].key,\n \t\t\t&signature[i]);\n \t\tflow_req[i].port_id = port_id[i];\n+\t\tflow_req[i].flow_id = flow_id[i];\n \t}\n \n \treq->type = PIPELINE_MSG_REQ_CUSTOM;\n@@ -535,6 +542,7 @@ app_pipeline_fc_add_bulk(struct app_params *app,\n \tfor (i = 0; i < rsp->n_keys; i++) {\n \t\tmemcpy(&flow[i]->key, &key[i], sizeof(flow[i]->key));\n \t\tflow[i]->port_id = port_id[i];\n+\t\tflow[i]->flow_id = flow_id[i];\n \t\tflow[i]->signature = signature[i];\n \t\tflow[i]->entry_ptr = flow_rsp[i].entry_ptr;\n \n@@ -731,13 +739,15 @@ print_fc_qinq_flow(struct app_pipeline_fc_flow *flow)\n {\n \tprintf(\"(SVLAN = %\" PRIu32 \", \"\n \t\t\"CVLAN = %\" PRIu32 \") => \"\n-\t\t\"Port = %\" PRIu32 \" \"\n+\t\t\"Port = %\" PRIu32 \", \"\n+\t\t\"Flow ID = %\" PRIu32 \", \"\n \t\t\"(signature = 0x%08\" PRIx32 \", \"\n \t\t\"entry_ptr = %p)\\n\",\n \n \t\tflow->key.key.qinq.svlan,\n \t\tflow->key.key.qinq.cvlan,\n \t\tflow->port_id,\n+\t\tflow->flow_id,\n \t\tflow->signature,\n \t\tflow->entry_ptr);\n }\n@@ -750,7 +760,8 @@ print_fc_ipv4_5tuple_flow(struct app_pipeline_fc_flow *flow)\n \t\t   \"SP = %\" PRIu32 \", \"\n \t\t   \"DP = %\" PRIu32 \", \"\n \t\t   \"Proto = %\" PRIu32 \") => \"\n-\t\t   \"Port = %\" PRIu32 \" \"\n+\t\t   \"Port = %\" PRIu32 \", \"\n+\t\t   \"Flow ID = %\" PRIu32 \" \"\n \t\t   \"(signature = 0x%08\" PRIx32 \", \"\n \t\t   \"entry_ptr = %p)\\n\",\n \n@@ -770,6 +781,7 @@ print_fc_ipv4_5tuple_flow(struct app_pipeline_fc_flow *flow)\n \t\t   flow->key.key.ipv4_5tuple.proto,\n \n \t\t   flow->port_id,\n+\t\t   flow->flow_id,\n \t\t   flow->signature,\n \t\t   flow->entry_ptr);\n }\n@@ -787,7 +799,8 @@ print_fc_ipv6_5tuple_flow(struct app_pipeline_fc_flow *flow) {\n \t\t\"SP = %\" PRIu32 \", \"\n \t\t\"DP = %\" PRIu32 \" \"\n \t\t\"Proto = %\" PRIu32 \" \"\n-\t\t\"=> Port = %\" PRIu32 \" \"\n+\t\t\"=> Port = %\" PRIu32 \", \"\n+\t\t\"Flow ID = %\" PRIu32 \" \"\n \t\t\"(signature = 0x%08\" PRIx32 \", \"\n \t\t\"entry_ptr = %p)\\n\",\n \n@@ -831,6 +844,7 @@ print_fc_ipv6_5tuple_flow(struct app_pipeline_fc_flow *flow) {\n \t\tflow->key.key.ipv6_5tuple.proto,\n \n \t\tflow->port_id,\n+\t\tflow->flow_id,\n \t\tflow->signature,\n \t\tflow->entry_ptr);\n }\n@@ -895,7 +909,10 @@ struct cmd_fc_add_qinq_result {\n \tcmdline_fixed_string_t qinq_string;\n \tuint16_t svlan;\n \tuint16_t cvlan;\n+\tcmdline_fixed_string_t port_string;\n \tuint32_t port;\n+\tcmdline_fixed_string_t flowid_string;\n+\tuint32_t flow_id;\n };\n \n static void\n@@ -917,7 +934,8 @@ cmd_fc_add_qinq_parsed(\n \tstatus = app_pipeline_fc_add(app,\n \t\tparams->pipeline_id,\n \t\t&key,\n-\t\tparams->port);\n+\t\tparams->port,\n+\t\tparams->flow_id);\n \tif (status != 0)\n \t\tprintf(\"Command failed\\n\");\n }\n@@ -947,9 +965,20 @@ cmdline_parse_token_num_t cmd_fc_add_qinq_svlan =\n cmdline_parse_token_num_t cmd_fc_add_qinq_cvlan =\n \tTOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, cvlan, UINT16);\n \n+cmdline_parse_token_string_t cmd_fc_add_qinq_port_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, port_string,\n+\t\t\"port\");\n+\n cmdline_parse_token_num_t cmd_fc_add_qinq_port =\n \tTOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, port, UINT32);\n \n+cmdline_parse_token_string_t cmd_fc_add_qinq_flowid_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, flowid_string,\n+\t\t\"flowid\");\n+\n+cmdline_parse_token_num_t cmd_fc_add_qinq_flow_id =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, flow_id, UINT32);\n+\n cmdline_parse_inst_t cmd_fc_add_qinq = {\n \t.f = cmd_fc_add_qinq_parsed,\n \t.data = NULL,\n@@ -962,7 +991,10 @@ cmdline_parse_inst_t cmd_fc_add_qinq = {\n \t\t(void *) &cmd_fc_add_qinq_qinq_string,\n \t\t(void *) &cmd_fc_add_qinq_svlan,\n \t\t(void *) &cmd_fc_add_qinq_cvlan,\n+\t\t(void *) &cmd_fc_add_qinq_port_string,\n \t\t(void *) &cmd_fc_add_qinq_port,\n+\t\t(void *) &cmd_fc_add_qinq_flowid_string,\n+\t\t(void *) &cmd_fc_add_qinq_flow_id,\n \t\tNULL,\n \t},\n };\n@@ -996,8 +1028,21 @@ cmd_fc_add_qinq_all_parsed(\n \tstruct app_params *app = data;\n \tstruct pipeline_fc_key *key;\n \tuint32_t *port_id;\n-\tuint32_t flow_id;\n+\tuint32_t *flow_id;\n+\tuint32_t id;\n \n+\t/* Check input arguments */\n+\tif (params->n_flows == 0) {\n+\t\tprintf(\"Invalid number of flows\\n\");\n+\t\treturn;\n+\t}\n+\n+\tif (params->n_ports == 0) {\n+\t\tprintf(\"Invalid number of output ports\\n\");\n+\t\treturn;\n+\t}\n+\n+\t/* Memory allocation */\n \tkey = rte_zmalloc(NULL,\n \t\tN_FLOWS_BULK * sizeof(*key),\n \t\tRTE_CACHE_LINE_SIZE);\n@@ -1015,23 +1060,36 @@ cmd_fc_add_qinq_all_parsed(\n \t\treturn;\n \t}\n \n-\tfor (flow_id = 0; flow_id < params->n_flows; flow_id++) {\n-\t\tuint32_t pos = flow_id & (N_FLOWS_BULK - 1);\n+\tflow_id = rte_malloc(NULL,\n+\t\tN_FLOWS_BULK * sizeof(*flow_id),\n+\t\tRTE_CACHE_LINE_SIZE);\n+\tif (flow_id == NULL) {\n+\t\trte_free(port_id);\n+\t\trte_free(key);\n+\t\tprintf(\"Memory allocation failed\\n\");\n+\t\treturn;\n+\t}\n+\n+\t/* Flow add */\n+\tfor (id = 0; id < params->n_flows; id++) {\n+\t\tuint32_t pos = id & (N_FLOWS_BULK - 1);\n \n \t\tkey[pos].type = FLOW_KEY_QINQ;\n-\t\tkey[pos].key.qinq.svlan = flow_id >> 12;\n-\t\tkey[pos].key.qinq.cvlan = flow_id & 0xFFF;\n+\t\tkey[pos].key.qinq.svlan = id >> 12;\n+\t\tkey[pos].key.qinq.cvlan = id & 0xFFF;\n \n-\t\tport_id[pos] = flow_id % params->n_ports;\n+\t\tport_id[pos] = id % params->n_ports;\n+\t\tflow_id[pos] = id;\n \n \t\tif ((pos == N_FLOWS_BULK - 1) ||\n-\t\t\t(flow_id == params->n_flows - 1)) {\n+\t\t\t(id == params->n_flows - 1)) {\n \t\t\tint status;\n \n \t\t\tstatus = app_pipeline_fc_add_bulk(app,\n \t\t\t\tparams->pipeline_id,\n \t\t\t\tkey,\n \t\t\t\tport_id,\n+\t\t\t\tflow_id,\n \t\t\t\tpos + 1);\n \n \t\t\tif (status != 0) {\n@@ -1042,6 +1100,8 @@ cmd_fc_add_qinq_all_parsed(\n \t\t}\n \t}\n \n+\t/* Memory free */\n+\trte_free(flow_id);\n \trte_free(port_id);\n \trte_free(key);\n }\n@@ -1110,7 +1170,10 @@ struct cmd_fc_add_ipv4_5tuple_result {\n \tuint16_t port_src;\n \tuint16_t port_dst;\n \tuint32_t proto;\n+\tcmdline_fixed_string_t port_string;\n \tuint32_t port;\n+\tcmdline_fixed_string_t flowid_string;\n+\tuint32_t flow_id;\n };\n \n static void\n@@ -1137,7 +1200,8 @@ cmd_fc_add_ipv4_5tuple_parsed(\n \tstatus = app_pipeline_fc_add(app,\n \t\tparams->pipeline_id,\n \t\t&key,\n-\t\tparams->port);\n+\t\tparams->port,\n+\t\tparams->flow_id);\n \tif (status != 0)\n \t\tprintf(\"Command failed\\n\");\n }\n@@ -1180,10 +1244,22 @@ cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_proto =\n \tTOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, proto,\n \t\tUINT32);\n \n+cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_port_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_string,\n+\t\t\"port\");\n+\n cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port =\n \tTOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port,\n \t\tUINT32);\n \n+cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_flowid_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result,\n+\t\tflowid_string, \"flowid\");\n+\n+cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_flow_id =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, flow_id,\n+\t\tUINT32);\n+\n cmdline_parse_inst_t cmd_fc_add_ipv4_5tuple = {\n \t.f = cmd_fc_add_ipv4_5tuple_parsed,\n \t.data = NULL,\n@@ -1199,7 +1275,10 @@ cmdline_parse_inst_t cmd_fc_add_ipv4_5tuple = {\n \t\t(void *) &cmd_fc_add_ipv4_5tuple_port_src,\n \t\t(void *) &cmd_fc_add_ipv4_5tuple_port_dst,\n \t\t(void *) &cmd_fc_add_ipv4_5tuple_proto,\n+\t\t(void *) &cmd_fc_add_ipv4_5tuple_port_string,\n \t\t(void *) &cmd_fc_add_ipv4_5tuple_port,\n+\t\t(void *) &cmd_fc_add_ipv4_5tuple_flowid_string,\n+\t\t(void *) &cmd_fc_add_ipv4_5tuple_flow_id,\n \t\tNULL,\n \t},\n };\n@@ -1229,8 +1308,21 @@ cmd_fc_add_ipv4_5tuple_all_parsed(\n \tstruct app_params *app = data;\n \tstruct pipeline_fc_key *key;\n \tuint32_t *port_id;\n-\tuint32_t flow_id;\n+\tuint32_t *flow_id;\n+\tuint32_t id;\n+\n+\t/* Check input parameters */\n+\tif (params->n_flows == 0) {\n+\t\tprintf(\"Invalid number of flows\\n\");\n+\t\treturn;\n+\t}\n \n+\tif (params->n_ports == 0) {\n+\t\tprintf(\"Invalid number of ports\\n\");\n+\t\treturn;\n+\t}\n+\n+\t/* Memory allocation */\n \tkey = rte_zmalloc(NULL,\n \t\tN_FLOWS_BULK * sizeof(*key),\n \t\tRTE_CACHE_LINE_SIZE);\n@@ -1248,26 +1340,39 @@ cmd_fc_add_ipv4_5tuple_all_parsed(\n \t\treturn;\n \t}\n \n-\tfor (flow_id = 0; flow_id < params->n_flows; flow_id++) {\n-\t\tuint32_t pos = flow_id & (N_FLOWS_BULK - 1);\n+\tflow_id = rte_malloc(NULL,\n+\t\tN_FLOWS_BULK * sizeof(*flow_id),\n+\t\tRTE_CACHE_LINE_SIZE);\n+\tif (flow_id == NULL) {\n+\t\trte_free(port_id);\n+\t\trte_free(key);\n+\t\tprintf(\"Memory allocation failed\\n\");\n+\t\treturn;\n+\t}\n+\n+\t/* Flow add */\n+\tfor (id = 0; id < params->n_flows; id++) {\n+\t\tuint32_t pos = id & (N_FLOWS_BULK - 1);\n \n \t\tkey[pos].type = FLOW_KEY_IPV4_5TUPLE;\n \t\tkey[pos].key.ipv4_5tuple.ip_src = 0;\n-\t\tkey[pos].key.ipv4_5tuple.ip_dst = flow_id;\n+\t\tkey[pos].key.ipv4_5tuple.ip_dst = id;\n \t\tkey[pos].key.ipv4_5tuple.port_src = 0;\n \t\tkey[pos].key.ipv4_5tuple.port_dst = 0;\n \t\tkey[pos].key.ipv4_5tuple.proto = 6;\n \n-\t\tport_id[pos] = flow_id % params->n_ports;\n+\t\tport_id[pos] = id % params->n_ports;\n+\t\tflow_id[pos] = id;\n \n \t\tif ((pos == N_FLOWS_BULK - 1) ||\n-\t\t\t(flow_id == params->n_flows - 1)) {\n+\t\t\t(id == params->n_flows - 1)) {\n \t\t\tint status;\n \n \t\t\tstatus = app_pipeline_fc_add_bulk(app,\n \t\t\t\tparams->pipeline_id,\n \t\t\t\tkey,\n \t\t\t\tport_id,\n+\t\t\t\tflow_id,\n \t\t\t\tpos + 1);\n \n \t\t\tif (status != 0) {\n@@ -1278,6 +1383,8 @@ cmd_fc_add_ipv4_5tuple_all_parsed(\n \t\t}\n \t}\n \n+\t/* Memory free */\n+\trte_free(flow_id);\n \trte_free(port_id);\n \trte_free(key);\n }\n@@ -1346,7 +1453,10 @@ struct cmd_fc_add_ipv6_5tuple_result {\n \tuint16_t port_src;\n \tuint16_t port_dst;\n \tuint32_t proto;\n+\tcmdline_fixed_string_t port_string;\n \tuint32_t port;\n+\tcmdline_fixed_string_t flowid_string;\n+\tuint32_t flow_id;\n };\n \n static void\n@@ -1375,7 +1485,8 @@ cmd_fc_add_ipv6_5tuple_parsed(\n \tstatus = app_pipeline_fc_add(app,\n \t\tparams->pipeline_id,\n \t\t&key,\n-\t\tparams->port);\n+\t\tparams->port,\n+\t\tparams->flow_id);\n \tif (status != 0)\n \t\tprintf(\"Command failed\\n\");\n }\n@@ -1418,10 +1529,22 @@ cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_proto =\n \tTOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, proto,\n \t\tUINT32);\n \n+cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_port_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,\n+\t\tport_string, \"port\");\n+\n cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port =\n \tTOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port,\n \t\tUINT32);\n \n+cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_flowid_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result,\n+\t\tflowid_string, \"flowid\");\n+\n+cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_flow_id =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, flow_id,\n+\t\tUINT32);\n+\n cmdline_parse_inst_t cmd_fc_add_ipv6_5tuple = {\n \t.f = cmd_fc_add_ipv6_5tuple_parsed,\n \t.data = NULL,\n@@ -1437,7 +1560,10 @@ cmdline_parse_inst_t cmd_fc_add_ipv6_5tuple = {\n \t\t(void *) &cmd_fc_add_ipv6_5tuple_port_src,\n \t\t(void *) &cmd_fc_add_ipv6_5tuple_port_dst,\n \t\t(void *) &cmd_fc_add_ipv6_5tuple_proto,\n+\t\t(void *) &cmd_fc_add_ipv6_5tuple_port_string,\n \t\t(void *) &cmd_fc_add_ipv6_5tuple_port,\n+\t\t(void *) &cmd_fc_add_ipv6_5tuple_flowid_string,\n+\t\t(void *) &cmd_fc_add_ipv6_5tuple_flow_id,\n \t\tNULL,\n \t},\n };\n@@ -1467,8 +1593,21 @@ cmd_fc_add_ipv6_5tuple_all_parsed(\n \tstruct app_params *app = data;\n \tstruct pipeline_fc_key *key;\n \tuint32_t *port_id;\n-\tuint32_t flow_id;\n+\tuint32_t *flow_id;\n+\tuint32_t id;\n+\n+\t/* Check input parameters */\n+\tif (params->n_flows == 0) {\n+\t\tprintf(\"Invalid number of flows\\n\");\n+\t\treturn;\n+\t}\n+\n+\tif (params->n_ports == 0) {\n+\t\tprintf(\"Invalid number of ports\\n\");\n+\t\treturn;\n+\t}\n \n+\t/* Memory allocation */\n \tkey = rte_zmalloc(NULL,\n \t\tN_FLOWS_BULK * sizeof(*key),\n \t\tRTE_CACHE_LINE_SIZE);\n@@ -1486,25 +1625,38 @@ cmd_fc_add_ipv6_5tuple_all_parsed(\n \t\treturn;\n \t}\n \n-\tfor (flow_id = 0; flow_id < params->n_flows; flow_id++) {\n-\t\tuint32_t pos = flow_id & (N_FLOWS_BULK - 1);\n+\tflow_id = rte_malloc(NULL,\n+\t\tN_FLOWS_BULK * sizeof(*flow_id),\n+\t\tRTE_CACHE_LINE_SIZE);\n+\tif (flow_id == NULL) {\n+\t\trte_free(port_id);\n+\t\trte_free(key);\n+\t\tprintf(\"Memory allocation failed\\n\");\n+\t\treturn;\n+\t}\n+\n+\t/* Flow add */\n+\tfor (id = 0; id < params->n_flows; id++) {\n+\t\tuint32_t pos = id & (N_FLOWS_BULK - 1);\n \t\tuint32_t *x;\n \n \t\tkey[pos].type = FLOW_KEY_IPV6_5TUPLE;\n \t\tx = (uint32_t *) key[pos].key.ipv6_5tuple.ip_dst;\n-\t\t*x = rte_bswap32(flow_id);\n+\t\t*x = rte_bswap32(id);\n \t\tkey[pos].key.ipv6_5tuple.proto = 6;\n \n-\t\tport_id[pos] = flow_id % params->n_ports;\n+\t\tport_id[pos] = id % params->n_ports;\n+\t\tflow_id[pos] = id;\n \n \t\tif ((pos == N_FLOWS_BULK - 1) ||\n-\t\t\t(flow_id == params->n_flows - 1)) {\n+\t\t\t(id == params->n_flows - 1)) {\n \t\t\tint status;\n \n \t\t\tstatus = app_pipeline_fc_add_bulk(app,\n \t\t\t\tparams->pipeline_id,\n \t\t\t\tkey,\n \t\t\t\tport_id,\n+\t\t\t\tflow_id,\n \t\t\t\tpos + 1);\n \n \t\t\tif (status != 0) {\n@@ -1515,6 +1667,8 @@ cmd_fc_add_ipv6_5tuple_all_parsed(\n \t\t}\n \t}\n \n+\t/* Memory free */\n+\trte_free(flow_id);\n \trte_free(port_id);\n \trte_free(key);\n }\ndiff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.h b/examples/ip_pipeline/pipeline/pipeline_flow_classification.h\nindex 7529314..9c77500 100644\n--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.h\n+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification.h\n@@ -77,13 +77,15 @@ int\n app_pipeline_fc_add(struct app_params *app,\n \tuint32_t pipeline_id,\n \tstruct pipeline_fc_key *key,\n-\tuint32_t port_id);\n+\tuint32_t port_id,\n+\tuint32_t flow_id);\n \n int\n app_pipeline_fc_add_bulk(struct app_params *app,\n \tuint32_t pipeline_id,\n \tstruct pipeline_fc_key *key,\n \tuint32_t *port_id,\n+\tuint32_t *flow_id,\n \tuint32_t n_keys);\n \n int\ndiff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c\nindex 06a648d..eb39a66 100644\n--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c\n+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c\n@@ -39,6 +39,7 @@\n #include <rte_byteorder.h>\n \n #include \"pipeline_flow_classification_be.h\"\n+#include \"pipeline_actions_common.h\"\n #include \"hash_func.h\"\n \n struct pipeline_flow_classification {\n@@ -46,9 +47,13 @@ struct pipeline_flow_classification {\n \tpipeline_msg_req_handler custom_handlers[PIPELINE_FC_MSG_REQS];\n \n \tuint32_t n_flows;\n-\tuint32_t key_offset;\n \tuint32_t key_size;\n+\tuint32_t flow_id;\n+\n+\tuint32_t key_offset;\n \tuint32_t hash_offset;\n+\tuint32_t flow_id_offset;\n+\n } __rte_cache_aligned;\n \n static void *\n@@ -104,6 +109,8 @@ static pipeline_msg_req_handler custom_handlers[] = {\n  */\n struct flow_table_entry {\n \tstruct rte_pipeline_table_entry head;\n+\n+\tuint32_t flow_id;\n };\n \n rte_table_hash_op_hash hash_func[] = {\n@@ -117,6 +124,86 @@ rte_table_hash_op_hash hash_func[] = {\n \thash_default_key64\n };\n \n+/*\n+ * Flow table AH - Write flow_id to packet meta-data\n+ */\n+static inline void\n+pkt_work_flow_id(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tstruct pipeline_flow_classification *p_fc = arg;\n+\tuint32_t *flow_id_ptr =\n+\t\tRTE_MBUF_METADATA_UINT32_PTR(pkt, p_fc->flow_id_offset);\n+\tstruct flow_table_entry *entry =\n+\t\t(struct flow_table_entry *) table_entry;\n+\n+\t/* Read */\n+\tuint32_t flow_id = entry->flow_id;\n+\n+\t/* Compute */\n+\n+\t/* Write */\n+\t*flow_id_ptr = flow_id;\n+}\n+\n+static inline void\n+pkt4_work_flow_id(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tstruct pipeline_flow_classification *p_fc = arg;\n+\n+\tuint32_t *flow_id_ptr0 =\n+\t\tRTE_MBUF_METADATA_UINT32_PTR(pkts[0], p_fc->flow_id_offset);\n+\tuint32_t *flow_id_ptr1 =\n+\t\tRTE_MBUF_METADATA_UINT32_PTR(pkts[1], p_fc->flow_id_offset);\n+\tuint32_t *flow_id_ptr2 =\n+\t\tRTE_MBUF_METADATA_UINT32_PTR(pkts[2], p_fc->flow_id_offset);\n+\tuint32_t *flow_id_ptr3 =\n+\t\tRTE_MBUF_METADATA_UINT32_PTR(pkts[3], p_fc->flow_id_offset);\n+\n+\tstruct flow_table_entry *entry0 =\n+\t\t(struct flow_table_entry *) table_entries[0];\n+\tstruct flow_table_entry *entry1 =\n+\t\t(struct flow_table_entry *) table_entries[1];\n+\tstruct flow_table_entry *entry2 =\n+\t\t(struct flow_table_entry *) table_entries[2];\n+\tstruct flow_table_entry *entry3 =\n+\t\t(struct flow_table_entry *) table_entries[3];\n+\n+\t/* Read */\n+\tuint32_t flow_id0 = entry0->flow_id;\n+\tuint32_t flow_id1 = entry1->flow_id;\n+\tuint32_t flow_id2 = entry2->flow_id;\n+\tuint32_t flow_id3 = entry3->flow_id;\n+\n+\t/* Compute */\n+\n+\t/* Write */\n+\t*flow_id_ptr0 = flow_id0;\n+\t*flow_id_ptr1 = flow_id1;\n+\t*flow_id_ptr2 = flow_id2;\n+\t*flow_id_ptr3 = flow_id3;\n+}\n+\n+PIPELINE_TABLE_AH_HIT(fc_table_ah_hit,\n+\t\tpkt_work_flow_id, pkt4_work_flow_id);\n+\n+static rte_pipeline_table_action_handler_hit\n+get_fc_table_ah_hit(struct pipeline_flow_classification *p)\n+{\n+\tif (p->flow_id)\n+\t\treturn fc_table_ah_hit;\n+\n+\treturn NULL;\n+}\n+\n+/*\n+ * Argument parsing\n+ */\n static int\n pipeline_fc_parse_args(struct pipeline_flow_classification *p,\n \tstruct pipeline_params *params)\n@@ -125,9 +212,12 @@ pipeline_fc_parse_args(struct pipeline_flow_classification *p,\n \tuint32_t key_offset_present = 0;\n \tuint32_t key_size_present = 0;\n \tuint32_t hash_offset_present = 0;\n-\n+\tuint32_t flow_id_offset_present = 0;\n \tuint32_t i;\n \n+\t/* default values */\n+\tp->flow_id = 0;\n+\n \tfor (i = 0; i < params->n_args; i++) {\n \t\tchar *arg_name = params->args_name[i];\n \t\tchar *arg_value = params->args_value[i];\n@@ -182,6 +272,18 @@ pipeline_fc_parse_args(struct pipeline_flow_classification *p,\n \t\t\tcontinue;\n \t\t}\n \n+\t\t/* flow_id_offset */\n+\t\tif (strcmp(arg_name, \"flowid_offset\") == 0) {\n+\t\t\tif (flow_id_offset_present)\n+\t\t\t\treturn -1;\n+\t\t\tflow_id_offset_present = 1;\n+\n+\t\t\tp->flow_id = 1;\n+\t\t\tp->flow_id_offset = atoi(arg_value);\n+\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\t/* Unknown argument */\n \t\treturn -1;\n \t}\n@@ -325,9 +427,9 @@ static void *pipeline_fc_init(struct pipeline_params *params,\n \t\tstruct rte_pipeline_table_params table_params = {\n \t\t\t.ops = NULL, /* set below */\n \t\t\t.arg_create = NULL, /* set below */\n-\t\t\t.f_action_hit = NULL,\n+\t\t\t.f_action_hit = get_fc_table_ah_hit(p_fc),\n \t\t\t.f_action_miss = NULL,\n-\t\t\t.arg_ah = NULL,\n+\t\t\t.arg_ah = p_fc,\n \t\t\t.action_data_size = sizeof(struct flow_table_entry) -\n \t\t\t\tsizeof(struct rte_pipeline_table_entry),\n \t\t};\n@@ -485,6 +587,7 @@ pipeline_fc_msg_req_add_handler(struct pipeline *p, void *msg)\n \t\t\t.action = RTE_PIPELINE_ACTION_PORT,\n \t\t\t{.port_id = p->port_out_id[req->port_id]},\n \t\t},\n+\t\t.flow_id = req->flow_id,\n \t};\n \n \trsp->status = rte_pipeline_table_entry_add(p->p,\n@@ -513,6 +616,7 @@ pipeline_fc_msg_req_add_bulk_handler(struct pipeline *p, void *msg)\n \t\t\t\t.action = RTE_PIPELINE_ACTION_PORT,\n \t\t\t\t{.port_id = p->port_out_id[flow_req->port_id]},\n \t\t\t},\n+\t\t\t.flow_id = flow_req->flow_id,\n \t\t};\n \n \t\tint status = rte_pipeline_table_entry_add(p->p,\n@@ -558,6 +662,8 @@ pipeline_fc_msg_req_add_default_handler(struct pipeline *p, void *msg)\n \t\t\t.action = RTE_PIPELINE_ACTION_PORT,\n \t\t\t{.port_id = p->port_out_id[req->port_id]},\n \t\t},\n+\n+\t\t.flow_id = 0,\n \t};\n \n \trsp->status = rte_pipeline_table_default_entry_add(p->p,\ndiff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h\nindex 46403d5..d8129b2 100644\n--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h\n+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h\n@@ -59,6 +59,7 @@ struct pipeline_fc_add_msg_req {\n \tuint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];\n \n \tuint32_t port_id;\n+\tuint32_t flow_id;\n };\n \n struct pipeline_fc_add_msg_rsp {\n@@ -73,6 +74,7 @@ struct pipeline_fc_add_msg_rsp {\n struct pipeline_fc_add_bulk_flow_req {\n \tuint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];\n \tuint32_t port_id;\n+\tuint32_t flow_id;\n };\n \n struct pipeline_fc_add_bulk_flow_rsp {\n",
    "prefixes": [
        "dpdk-dev"
    ]
}