get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 139703,
    "url": "http://patches.dpdk.org/api/patches/139703/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20240426122203.32357-3-nsaxena@marvell.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": "<20240426122203.32357-3-nsaxena@marvell.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20240426122203.32357-3-nsaxena@marvell.com",
    "date": "2024-04-26T12:22:03",
    "name": "[RFC,2/2] graph: add ip4 output feature arc",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "919f47171a30bb0f664a343c318e22678718571b",
    "submitter": {
        "id": 3320,
        "url": "http://patches.dpdk.org/api/people/3320/?format=api",
        "name": "Nitin Saxena",
        "email": "nsaxena@marvell.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/20240426122203.32357-3-nsaxena@marvell.com/mbox/",
    "series": [
        {
            "id": 31832,
            "url": "http://patches.dpdk.org/api/series/31832/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=31832",
            "date": "2024-04-26T12:22:03",
            "name": "add feature arc in rte_graph",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/31832/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/139703/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/139703/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 9CB3943F15;\n\tFri, 26 Apr 2024 14:22:53 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 83A8A43DB0;\n\tFri, 26 Apr 2024 14:22:53 +0200 (CEST)",
            "from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com\n [67.231.148.174])\n by mails.dpdk.org (Postfix) with ESMTP id 73D0243CE3\n for <dev@dpdk.org>; Fri, 26 Apr 2024 14:22:51 +0200 (CEST)",
            "from pps.filterd (m0045849.ppops.net [127.0.0.1])\n by mx0a-0016f401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id\n 43Q9hLbr027079;\n Fri, 26 Apr 2024 05:22:46 -0700",
            "from dc6wp-exch02.marvell.com ([4.21.29.225])\n by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 3xr9vp0cw1-2\n (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT);\n Fri, 26 Apr 2024 05:22:45 -0700 (PDT)",
            "from DC6WP-EXCH02.marvell.com (10.76.176.209) by\n DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server\n (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.2.1544.4; Fri, 26 Apr 2024 05:22:11 -0700",
            "from maili.marvell.com (10.69.176.80) by DC6WP-EXCH02.marvell.com\n (10.76.176.209) with Microsoft SMTP Server id 15.2.1544.4 via Frontend\n Transport; Fri, 26 Apr 2024 05:22:11 -0700",
            "from localhost.localdomain (unknown [10.28.36.207])\n by maili.marvell.com (Postfix) with ESMTP id A3C733F7069;\n Fri, 26 Apr 2024 05:22:09 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=\n from:to:cc:subject:date:message-id:in-reply-to:references\n :mime-version:content-transfer-encoding:content-type; s=\n pfpt0220; bh=ajgiyoOfWxecEEKIV1mUxs2gzgbm1W5yREDFxsXpMv0=; b=NP+\n 0J4nbRm8WIx8jCsDBsRbBhGR61MLcH5ekMdGXdyDmDO0JLBWWZsHQORkzUmv8Pde\n 5+je+8uu6/v+bUmbkdolVjKx8Nvh+dNJR1UUBC0vDDdyqLb+4krkV5ZZ2g+AmTvS\n Kh3CHRadx/GW2wu8MYX6wi27ACN94jjlMdeD71/BFcznXtwyoJIMP4/JTWiaOKdT\n hLmbywx9PqLKy4z4SKUs7yzE2/ra+cOcd/3A2LCydl7qXSQnzDRArQ3qO9YkTwSM\n raDTh6bblT2XNkK7IqTeZTVlhVQBeV+0BeVMdwgrJyTMR49BNoBLPicRHLwCaz32\n oorrUkPlepUzUFKvEgA==",
        "From": "Nitin Saxena <nsaxena@marvell.com>",
        "To": "Jerin Jacob <jerinj@marvell.com>, Kiran Kumar K <kirankumark@marvell.com>,\n Nithin Dabilpuram <ndabilpuram@marvell.com>, Zhirun Yan\n <yanzhirun_163@163.com>",
        "CC": "<dev@dpdk.org>",
        "Subject": "[RFC PATCH 2/2] graph: add ip4 output feature arc",
        "Date": "Fri, 26 Apr 2024 17:52:03 +0530",
        "Message-ID": "<20240426122203.32357-3-nsaxena@marvell.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20240426122203.32357-1-nsaxena@marvell.com>",
        "References": "<20240426122203.32357-1-nsaxena@marvell.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-Proofpoint-ORIG-GUID": "NrbzTnAB55pETtRdxnghkcEv9IkBjJG8",
        "X-Proofpoint-GUID": "NrbzTnAB55pETtRdxnghkcEv9IkBjJG8",
        "X-Proofpoint-Virus-Version": "vendor=baseguard\n engine=ICAP:2.0.293,Aquarius:18.0.1011,Hydra:6.0.650,FMLib:17.11.176.26\n definitions=2024-04-26_12,2024-04-26_02,2023-05-22_02",
        "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": "Signed-off-by: Nitin Saxena <nsaxena@marvell.com>\nChange-Id: I80021403c343354c7e494c6bc79b83b0d0fe6b7c\n---\n lib/node/ip4_rewrite.c      | 278 ++++++++++++++++++++++++++++--------\n lib/node/ip4_rewrite_priv.h |  10 +-\n lib/node/node_private.h     |  10 +-\n lib/node/rte_node_ip4_api.h |   3 +\n 4 files changed, 233 insertions(+), 68 deletions(-)",
    "diff": "diff --git a/lib/node/ip4_rewrite.c b/lib/node/ip4_rewrite.c\nindex 34a920df5e..60efd6b171 100644\n--- a/lib/node/ip4_rewrite.c\n+++ b/lib/node/ip4_rewrite.c\n@@ -20,6 +20,7 @@ struct ip4_rewrite_node_ctx {\n \tint mbuf_priv1_off;\n \t/* Cached next index */\n \tuint16_t next_index;\n+\trte_graph_feature_arc_t output_feature_arc;\n };\n \n static struct ip4_rewrite_node_main *ip4_rewrite_nm;\n@@ -30,21 +31,34 @@ static struct ip4_rewrite_node_main *ip4_rewrite_nm;\n #define IP4_REWRITE_NODE_PRIV1_OFF(ctx) \\\n \t(((struct ip4_rewrite_node_ctx *)ctx)->mbuf_priv1_off)\n \n+#define IP4_REWRITE_NODE_OUTPUT_FEATURE_ARC(ctx) \\\n+\t(((struct ip4_rewrite_node_ctx *)ctx)->output_feature_arc)\n+\n static uint16_t\n ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,\n \t\t\t void **objs, uint16_t nb_objs)\n {\n+\trte_graph_feature_arc_t out_feature_arc = IP4_REWRITE_NODE_OUTPUT_FEATURE_ARC(node->ctx);\n+\tuint16_t next0 = 0, next1 = 0, next2 = 0, next3 = 0, next_index;\n \tstruct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;\n \tstruct ip4_rewrite_nh_header *nh = ip4_rewrite_nm->nh;\n \tconst int dyn = IP4_REWRITE_NODE_PRIV1_OFF(node->ctx);\n-\tuint16_t next0, next1, next2, next3, next_index;\n-\tstruct rte_ipv4_hdr *ip0, *ip1, *ip2, *ip3;\n \tuint16_t n_left_from, held = 0, last_spec = 0;\n+\tstruct rte_ipv4_hdr *ip0, *ip1, *ip2, *ip3;\n+\tint b0_feat, b1_feat, b2_feat, b3_feat;\n+\trte_graph_feature_t f0, f1, f2, f3;\n+\tuint16_t tx0, tx1, tx2, tx3;\n+\tint64_t fd0, fd1, fd2, fd3;\n \tvoid *d0, *d1, *d2, *d3;\n \tvoid **to_next, **from;\n \trte_xmm_t priv01;\n \trte_xmm_t priv23;\n-\tint i;\n+\tint i, has_feat;\n+\n+\tRTE_SET_USED(fd0);\n+\tRTE_SET_USED(fd1);\n+\tRTE_SET_USED(fd2);\n+\tRTE_SET_USED(fd3);\n \n \t/* Speculative next as last next */\n \tnext_index = IP4_REWRITE_NODE_LAST_NEXT(node->ctx);\n@@ -83,54 +97,167 @@ ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,\n \t\tpriv23.u64[0] = node_mbuf_priv1(mbuf2, dyn)->u;\n \t\tpriv23.u64[1] = node_mbuf_priv1(mbuf3, dyn)->u;\n \n-\t\t/* Increment checksum by one. */\n-\t\tpriv01.u32[1] += rte_cpu_to_be_16(0x0100);\n-\t\tpriv01.u32[3] += rte_cpu_to_be_16(0x0100);\n-\t\tpriv23.u32[1] += rte_cpu_to_be_16(0x0100);\n-\t\tpriv23.u32[3] += rte_cpu_to_be_16(0x0100);\n-\n-\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf0 */\n-\t\td0 = rte_pktmbuf_mtod(mbuf0, void *);\n-\t\trte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,\n-\t\t\t   nh[priv01.u16[0]].rewrite_len);\n-\n-\t\tnext0 = nh[priv01.u16[0]].tx_node;\n-\t\tip0 = (struct rte_ipv4_hdr *)((uint8_t *)d0 +\n-\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n-\t\tip0->time_to_live = priv01.u16[1] - 1;\n-\t\tip0->hdr_checksum = priv01.u16[2] + priv01.u16[3];\n-\n-\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf1 */\n-\t\td1 = rte_pktmbuf_mtod(mbuf1, void *);\n-\t\trte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,\n-\t\t\t   nh[priv01.u16[4]].rewrite_len);\n-\n-\t\tnext1 = nh[priv01.u16[4]].tx_node;\n-\t\tip1 = (struct rte_ipv4_hdr *)((uint8_t *)d1 +\n-\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n-\t\tip1->time_to_live = priv01.u16[5] - 1;\n-\t\tip1->hdr_checksum = priv01.u16[6] + priv01.u16[7];\n-\n-\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf2 */\n-\t\td2 = rte_pktmbuf_mtod(mbuf2, void *);\n-\t\trte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,\n-\t\t\t   nh[priv23.u16[0]].rewrite_len);\n-\t\tnext2 = nh[priv23.u16[0]].tx_node;\n-\t\tip2 = (struct rte_ipv4_hdr *)((uint8_t *)d2 +\n-\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n-\t\tip2->time_to_live = priv23.u16[1] - 1;\n-\t\tip2->hdr_checksum = priv23.u16[2] + priv23.u16[3];\n-\n-\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf3 */\n-\t\td3 = rte_pktmbuf_mtod(mbuf3, void *);\n-\t\trte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,\n-\t\t\t   nh[priv23.u16[4]].rewrite_len);\n-\n-\t\tnext3 = nh[priv23.u16[4]].tx_node;\n-\t\tip3 = (struct rte_ipv4_hdr *)((uint8_t *)d3 +\n-\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n-\t\tip3->time_to_live = priv23.u16[5] - 1;\n-\t\tip3->hdr_checksum = priv23.u16[6] + priv23.u16[7];\n+\t\tf0 = nh[priv01.u16[0]].nh_feature;\n+\t\tf1 = nh[priv01.u16[4]].nh_feature;\n+\t\tf2 = nh[priv23.u16[0]].nh_feature;\n+\t\tf3 = nh[priv23.u16[4]].nh_feature;\n+\n+\t\ttx0 = nh[priv01.u16[0]].tx_node - 1;\n+\t\ttx1 = nh[priv01.u16[4]].tx_node - 1;\n+\t\ttx2 = nh[priv23.u16[0]].tx_node - 1;\n+\t\ttx3 = nh[priv23.u16[4]].tx_node - 1;\n+\n+\t\tb0_feat = rte_graph_feature_arc_has_feature(out_feature_arc, tx0, &f0);\n+\t\tb1_feat = rte_graph_feature_arc_has_feature(out_feature_arc, tx1, &f1);\n+\t\tb2_feat = rte_graph_feature_arc_has_feature(out_feature_arc, tx2, &f2);\n+\t\tb3_feat = rte_graph_feature_arc_has_feature(out_feature_arc, tx3, &f3);\n+\n+\t\thas_feat = b0_feat | b1_feat | b2_feat | b3_feat;\n+\n+\t\tif (unlikely(has_feat)) {\n+\t\t\t/* prefetch feature data */\n+\t\t\trte_graph_feature_data_prefetch(out_feature_arc, tx0, f0);\n+\t\t\trte_graph_feature_data_prefetch(out_feature_arc, tx1, f1);\n+\t\t\trte_graph_feature_data_prefetch(out_feature_arc, tx2, f2);\n+\t\t\trte_graph_feature_data_prefetch(out_feature_arc, tx3, f3);\n+\n+\t\t\t/* Save feature into mbuf */\n+\t\t\tnode_mbuf_priv1(mbuf0, dyn)->current_feature = f0;\n+\t\t\tnode_mbuf_priv1(mbuf1, dyn)->current_feature = f1;\n+\t\t\tnode_mbuf_priv1(mbuf2, dyn)->current_feature = f2;\n+\t\t\tnode_mbuf_priv1(mbuf3, dyn)->current_feature = f3;\n+\n+\t\t\t/* Save index into mbuf for next feature node */\n+\t\t\tnode_mbuf_priv1(mbuf0, dyn)->index = tx0;\n+\t\t\tnode_mbuf_priv1(mbuf1, dyn)->index = tx1;\n+\t\t\tnode_mbuf_priv1(mbuf2, dyn)->index = tx2;\n+\t\t\tnode_mbuf_priv1(mbuf3, dyn)->index = tx3;\n+\n+\t\t\t/* Does all of them have feature enabled */\n+\t\t\thas_feat = b0_feat && b1_feat && b2_feat && b3_feat;\n+\t\t\tif (has_feat) {\n+\t\t\t\trte_graph_feature_arc_feature_data_get(out_feature_arc,\n+\t\t\t\t\t\t\t\t       f0, tx0, &next0, &fd0);\n+\t\t\t\trte_graph_feature_arc_feature_data_get(out_feature_arc,\n+\t\t\t\t\t\t\t\t       f1, tx1, &next1, &fd1);\n+\t\t\t\trte_graph_feature_arc_feature_data_get(out_feature_arc,\n+\t\t\t\t\t\t\t\t       f2, tx2, &next2, &fd2);\n+\t\t\t\trte_graph_feature_arc_feature_data_get(out_feature_arc,\n+\t\t\t\t\t\t\t\t       f3, tx3, &next3, &fd3);\n+\t\t\t} else {\n+\t\t\t\tif (b0_feat) {\n+\t\t\t\t\trte_graph_feature_arc_feature_data_get(out_feature_arc, f0,\n+\t\t\t\t\t\t\t\t\t       tx0, &next0, &fd0);\n+\t\t\t\t} else {\n+\t\t\t\t\tpriv01.u32[1] += rte_cpu_to_be_16(0x0100);\n+\t\t\t\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf0 */\n+\t\t\t\t\td0 = rte_pktmbuf_mtod(mbuf0, void *);\n+\t\t\t\t\trte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,\n+\t\t\t\t\t\t   nh[priv01.u16[0]].rewrite_len);\n+\n+\t\t\t\t\tnext0 = tx0 + 1;\n+\t\t\t\t\tip0 = (struct rte_ipv4_hdr *)((uint8_t *)d0 +\n+\t\t\t\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n+\t\t\t\t\tip0->time_to_live = priv01.u16[1] - 1;\n+\t\t\t\t\tip0->hdr_checksum = priv01.u16[2] + priv01.u16[3];\n+\t\t\t\t}\n+\t\t\t\tif (b1_feat) {\n+\t\t\t\t\trte_graph_feature_arc_feature_data_get(out_feature_arc, f1,\n+\t\t\t\t\t\t\t\t\t       tx1, &next1, &fd1);\n+\t\t\t\t} else {\n+\t\t\t\t\tpriv01.u32[3] += rte_cpu_to_be_16(0x0100);\n+\t\t\t\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf1 */\n+\t\t\t\t\td1 = rte_pktmbuf_mtod(mbuf1, void *);\n+\t\t\t\t\trte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,\n+\t\t\t\t\t\t   nh[priv01.u16[4]].rewrite_len);\n+\n+\t\t\t\t\tnext1 = tx1 + 1;\n+\t\t\t\t\tip1 = (struct rte_ipv4_hdr *)((uint8_t *)d1 +\n+\t\t\t\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n+\t\t\t\t\tip1->time_to_live = priv01.u16[5] - 1;\n+\t\t\t\t\tip1->hdr_checksum = priv01.u16[6] + priv01.u16[7];\n+\t\t\t\t}\n+\t\t\t\tif (b2_feat) {\n+\t\t\t\t\trte_graph_feature_arc_feature_data_get(out_feature_arc, f2,\n+\t\t\t\t\t\t\t\t\t       tx2, &next2, &fd2);\n+\t\t\t\t} else {\n+\t\t\t\t\tpriv23.u32[1] += rte_cpu_to_be_16(0x0100);\n+\t\t\t\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf2 */\n+\t\t\t\t\td2 = rte_pktmbuf_mtod(mbuf2, void *);\n+\t\t\t\t\trte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,\n+\t\t\t\t\t\t   nh[priv23.u16[0]].rewrite_len);\n+\t\t\t\t\tnext2 = tx2 + 1;\n+\t\t\t\t\tip2 = (struct rte_ipv4_hdr *)((uint8_t *)d2 +\n+\t\t\t\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n+\t\t\t\t\tip2->time_to_live = priv23.u16[1] - 1;\n+\t\t\t\t\tip2->hdr_checksum = priv23.u16[2] + priv23.u16[3];\n+\t\t\t\t}\n+\t\t\t\tif (b3_feat) {\n+\t\t\t\t\trte_graph_feature_arc_feature_data_get(out_feature_arc, f3,\n+\t\t\t\t\t\t\t\t\t       tx3, &next1, &fd3);\n+\t\t\t\t} else {\n+\t\t\t\t\tpriv23.u32[3] += rte_cpu_to_be_16(0x0100);\n+\t\t\t\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf3 */\n+\t\t\t\t\td3 = rte_pktmbuf_mtod(mbuf3, void *);\n+\t\t\t\t\trte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,\n+\t\t\t\t\t\t   nh[priv23.u16[4]].rewrite_len);\n+\t\t\t\t\tnext3 = tx3 + 1;\n+\t\t\t\t\tip3 = (struct rte_ipv4_hdr *)((uint8_t *)d3 +\n+\t\t\t\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n+\t\t\t\t\tip3->time_to_live = priv23.u16[5] - 1;\n+\t\t\t\t\tip3->hdr_checksum = priv23.u16[6] + priv23.u16[7];\n+\t\t\t\t}\n+\t\t\t}\n+\t\t} else {\n+\t\t\t/* Increment checksum by one. */\n+\t\t\tpriv01.u32[1] += rte_cpu_to_be_16(0x0100);\n+\t\t\tpriv01.u32[3] += rte_cpu_to_be_16(0x0100);\n+\t\t\tpriv23.u32[1] += rte_cpu_to_be_16(0x0100);\n+\t\t\tpriv23.u32[3] += rte_cpu_to_be_16(0x0100);\n+\n+\t\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf0 */\n+\t\t\td0 = rte_pktmbuf_mtod(mbuf0, void *);\n+\t\t\trte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,\n+\t\t\t\t   nh[priv01.u16[0]].rewrite_len);\n+\n+\t\t\tnext0 = tx0 + 1;\n+\t\t\tip0 = (struct rte_ipv4_hdr *)((uint8_t *)d0 +\n+\t\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n+\t\t\tip0->time_to_live = priv01.u16[1] - 1;\n+\t\t\tip0->hdr_checksum = priv01.u16[2] + priv01.u16[3];\n+\n+\t\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf1 */\n+\t\t\td1 = rte_pktmbuf_mtod(mbuf1, void *);\n+\t\t\trte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,\n+\t\t\t\t   nh[priv01.u16[4]].rewrite_len);\n+\n+\t\t\tnext1 = tx1 + 1;\n+\t\t\tip1 = (struct rte_ipv4_hdr *)((uint8_t *)d1 +\n+\t\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n+\t\t\tip1->time_to_live = priv01.u16[5] - 1;\n+\t\t\tip1->hdr_checksum = priv01.u16[6] + priv01.u16[7];\n+\n+\t\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf2 */\n+\t\t\td2 = rte_pktmbuf_mtod(mbuf2, void *);\n+\t\t\trte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,\n+\t\t\t\t   nh[priv23.u16[0]].rewrite_len);\n+\t\t\tnext2 = tx2 + 1;\n+\t\t\tip2 = (struct rte_ipv4_hdr *)((uint8_t *)d2 +\n+\t\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n+\t\t\tip2->time_to_live = priv23.u16[1] - 1;\n+\t\t\tip2->hdr_checksum = priv23.u16[2] + priv23.u16[3];\n+\n+\t\t\t/* Update ttl,cksum rewrite ethernet hdr on mbuf3 */\n+\t\t\td3 = rte_pktmbuf_mtod(mbuf3, void *);\n+\t\t\trte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,\n+\t\t\t\t   nh[priv23.u16[4]].rewrite_len);\n+\n+\t\t\tnext3 = tx3 + 1;\n+\t\t\tip3 = (struct rte_ipv4_hdr *)((uint8_t *)d3 +\n+\t\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n+\t\t\tip3->time_to_live = priv23.u16[5] - 1;\n+\t\t\tip3->hdr_checksum = priv23.u16[6] + priv23.u16[7];\n+\t\t}\n \n \t\t/* Enqueue four to next node */\n \t\trte_edge_t fix_spec =\n@@ -212,19 +339,28 @@ ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,\n \t\tpkts += 1;\n \t\tn_left_from -= 1;\n \n-\t\td0 = rte_pktmbuf_mtod(mbuf0, void *);\n-\t\trte_memcpy(d0, nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_data,\n-\t\t\t   nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_len);\n-\n-\t\tnext0 = nh[node_mbuf_priv1(mbuf0, dyn)->nh].tx_node;\n-\t\tip0 = (struct rte_ipv4_hdr *)((uint8_t *)d0 +\n-\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n-\t\tchksum = node_mbuf_priv1(mbuf0, dyn)->cksum +\n-\t\t\t rte_cpu_to_be_16(0x0100);\n-\t\tchksum += chksum >= 0xffff;\n-\t\tip0->hdr_checksum = chksum;\n-\t\tip0->time_to_live = node_mbuf_priv1(mbuf0, dyn)->ttl - 1;\n+\t\ttx0 = nh[node_mbuf_priv1(mbuf0, dyn)->nh].tx_node - 1;\n+\t\tf0 = nh[node_mbuf_priv1(mbuf0, dyn)->nh].nh_feature;\n \n+\t\tif (unlikely(rte_graph_feature_arc_has_feature(out_feature_arc, tx0, &f0))) {\n+\t\t\trte_graph_feature_arc_feature_data_get(out_feature_arc, f0, tx0,\n+\t\t\t\t\t\t\t       &next0, &fd0);\n+\t\t\tnode_mbuf_priv1(mbuf0, dyn)->current_feature = f0;\n+\t\t\tnode_mbuf_priv1(mbuf0, dyn)->index = tx0;\n+\t\t} else {\n+\t\t\td0 = rte_pktmbuf_mtod(mbuf0, void *);\n+\t\t\trte_memcpy(d0, nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_data,\n+\t\t\t\t   nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_len);\n+\n+\t\t\tnext0 = tx0 + 1;\n+\t\t\tip0 = (struct rte_ipv4_hdr *)((uint8_t *)d0 +\n+\t\t\t\t\t\t      sizeof(struct rte_ether_hdr));\n+\t\t\tchksum = node_mbuf_priv1(mbuf0, dyn)->cksum +\n+\t\t\t\t rte_cpu_to_be_16(0x0100);\n+\t\t\tchksum += chksum >= 0xffff;\n+\t\t\tip0->hdr_checksum = chksum;\n+\t\t\tip0->time_to_live = node_mbuf_priv1(mbuf0, dyn)->ttl - 1;\n+\t\t}\n \t\tif (unlikely(next_index ^ next0)) {\n \t\t\t/* Copy things successfully speculated till now */\n \t\t\trte_memcpy(to_next, from, last_spec * sizeof(from[0]));\n@@ -258,19 +394,34 @@ ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,\n static int\n ip4_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)\n {\n+\trte_graph_feature_arc_t feature_arc = RTE_GRAPH_FEATURE_ARC_INITIALIZER;\n \tstatic bool init_once;\n \n \tRTE_SET_USED(graph);\n \tRTE_BUILD_BUG_ON(sizeof(struct ip4_rewrite_node_ctx) > RTE_NODE_CTX_SZ);\n+\tRTE_BUILD_BUG_ON(sizeof(struct ip4_rewrite_nh_header) != RTE_CACHE_LINE_MIN_SIZE);\n \n \tif (!init_once) {\n \t\tnode_mbuf_priv1_dynfield_offset = rte_mbuf_dynfield_register(\n \t\t\t\t&node_mbuf_priv1_dynfield_desc);\n \t\tif (node_mbuf_priv1_dynfield_offset < 0)\n \t\t\treturn -rte_errno;\n+\n+\t\t/* Create ipv4-output feature arc, if not created\n+\t\t */\n+\t\tif (rte_graph_feature_arc_lookup_by_name(RTE_IP4_OUTPUT_FEATURE_ARC_NAME, NULL) &&\n+\t\t    rte_graph_feature_arc_create(RTE_IP4_OUTPUT_FEATURE_ARC_NAME,\n+\t\t\t\t\t\t RTE_GRAPH_FEATURE_MAX_PER_ARC, /* max features */\n+\t\t\t\t\t\t RTE_MAX_ETHPORTS + 1, /* max output interfaces */\n+\t\t\t\t\t\t ip4_rewrite_node_get(),\n+\t\t\t\t\t\t &feature_arc)) {\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\n \t\tinit_once = true;\n \t}\n \tIP4_REWRITE_NODE_PRIV1_OFF(node->ctx) = node_mbuf_priv1_dynfield_offset;\n+\tIP4_REWRITE_NODE_OUTPUT_FEATURE_ARC(node->ctx) = feature_arc;\n \n \tnode_dbg(\"ip4_rewrite\", \"Initialized ip4_rewrite node initialized\");\n \n@@ -323,6 +474,7 @@ rte_node_ip4_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,\n \tnh->tx_node = ip4_rewrite_nm->next_index[dst_port];\n \tnh->rewrite_len = rewrite_len;\n \tnh->enabled = true;\n+\tnh->nh_feature = RTE_GRAPH_FEATURE_INVALID_VALUE;\n \n \treturn 0;\n }\ndiff --git a/lib/node/ip4_rewrite_priv.h b/lib/node/ip4_rewrite_priv.h\nindex 5105ec1d29..8b868026bf 100644\n--- a/lib/node/ip4_rewrite_priv.h\n+++ b/lib/node/ip4_rewrite_priv.h\n@@ -5,9 +5,10 @@\n #define __INCLUDE_IP4_REWRITE_PRIV_H__\n \n #include <rte_common.h>\n+#include <rte_graph_feature_arc.h>\n \n #define RTE_GRAPH_IP4_REWRITE_MAX_NH 64\n-#define RTE_GRAPH_IP4_REWRITE_MAX_LEN 56\n+#define RTE_GRAPH_IP4_REWRITE_MAX_LEN 53\n \n /**\n  * @internal\n@@ -15,11 +16,10 @@\n  * Ipv4 rewrite next hop header data structure. Used to store port specific\n  * rewrite data.\n  */\n-struct ip4_rewrite_nh_header {\n+struct __rte_cache_min_aligned ip4_rewrite_nh_header {\n \tuint16_t rewrite_len; /**< Header rewrite length. */\n \tuint16_t tx_node;     /**< Tx node next index identifier. */\n-\tuint16_t enabled;     /**< NH enable flag */\n-\tuint16_t rsvd;\n+\trte_graph_feature_t nh_feature;\n \tunion {\n \t\tstruct {\n \t\t\tstruct rte_ether_addr dst;\n@@ -30,6 +30,8 @@ struct ip4_rewrite_nh_header {\n \t\tuint8_t rewrite_data[RTE_GRAPH_IP4_REWRITE_MAX_LEN];\n \t\t/**< Generic rewrite data */\n \t};\n+\t/* used in control path */\n+\tuint8_t enabled;     /**< NH enable flag */\n };\n \n /**\ndiff --git a/lib/node/node_private.h b/lib/node/node_private.h\nindex 1de7306792..36f6e05624 100644\n--- a/lib/node/node_private.h\n+++ b/lib/node/node_private.h\n@@ -12,6 +12,9 @@\n #include <rte_mbuf.h>\n #include <rte_mbuf_dyn.h>\n \n+#include <rte_graph_worker_common.h>\n+#include <rte_graph_feature_arc_worker.h>\n+\n extern int rte_node_logtype;\n #define RTE_LOGTYPE_NODE rte_node_logtype\n \n@@ -35,9 +38,14 @@ struct node_mbuf_priv1 {\n \t\t\tuint16_t ttl;\n \t\t\tuint32_t cksum;\n \t\t};\n-\n \t\tuint64_t u;\n \t};\n+\tstruct {\n+\t\t/** feature that current mbuf holds */\n+\t\trte_graph_feature_t current_feature;\n+\t\t/** interface index */\n+\t\tuint32_t index;\n+\t};\n };\n \n static const struct rte_mbuf_dynfield node_mbuf_priv1_dynfield_desc = {\ndiff --git a/lib/node/rte_node_ip4_api.h b/lib/node/rte_node_ip4_api.h\nindex 24f8ec843a..0de06f7fc7 100644\n--- a/lib/node/rte_node_ip4_api.h\n+++ b/lib/node/rte_node_ip4_api.h\n@@ -23,6 +23,7 @@ extern \"C\" {\n #include <rte_compat.h>\n \n #include <rte_graph.h>\n+#include <rte_graph_feature_arc_worker.h>\n \n /**\n  * IP4 lookup next nodes.\n@@ -67,6 +68,8 @@ struct rte_node_ip4_reassembly_cfg {\n \t/**< Node identifier to configure. */\n };\n \n+#define RTE_IP4_OUTPUT_FEATURE_ARC_NAME \"ipv4-output\"\n+\n /**\n  * Add ipv4 route to lookup table.\n  *\n",
    "prefixes": [
        "RFC",
        "2/2"
    ]
}