get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 128498,
    "url": "https://patches.dpdk.org/api/patches/128498/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20230610201710.929-1-tanxeel1.ahmed@gmail.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": "<20230610201710.929-1-tanxeel1.ahmed@gmail.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20230610201710.929-1-tanxeel1.ahmed@gmail.com",
    "date": "2023-06-10T20:17:10",
    "name": "[v5] lib/net: add MPLS insert and strip functionality",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "b25ec8ca197b17107c8392143ff2ecdfdfaa2675",
    "submitter": {
        "id": 2915,
        "url": "https://patches.dpdk.org/api/people/2915/?format=api",
        "name": "Tanzeel Ahmed",
        "email": "tanxeel1.ahmed@gmail.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/20230610201710.929-1-tanxeel1.ahmed@gmail.com/mbox/",
    "series": [
        {
            "id": 28445,
            "url": "https://patches.dpdk.org/api/series/28445/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=28445",
            "date": "2023-06-10T20:17:10",
            "name": "[v5] lib/net: add MPLS insert and strip functionality",
            "version": 5,
            "mbox": "https://patches.dpdk.org/series/28445/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/128498/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/128498/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 9117D42C73;\n\tSat, 10 Jun 2023 22:17:25 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 1EB97410EF;\n\tSat, 10 Jun 2023 22:17:25 +0200 (CEST)",
            "from mail-pf1-f182.google.com (mail-pf1-f182.google.com\n [209.85.210.182])\n by mails.dpdk.org (Postfix) with ESMTP id 0D83740DD8\n for <dev@dpdk.org>; Sat, 10 Jun 2023 22:17:23 +0200 (CEST)",
            "by mail-pf1-f182.google.com with SMTP id\n d2e1a72fcca58-655fce0f354so2480423b3a.0\n for <dev@dpdk.org>; Sat, 10 Jun 2023 13:17:23 -0700 (PDT)",
            "from DESKTOP-KPIMD3E.localdomain\n ([2407:d000:f:612c:6d4f:2e76:df27:2e72])\n by smtp.gmail.com with ESMTPSA id\n a192-20020a6390c9000000b0051b4a163ccdsm4812369pge.11.2023.06.10.13.17.18\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Sat, 10 Jun 2023 13:17:22 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20221208; t=1686428243; x=1689020243;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=kSxa0ZgoyozgWrQqCFL1esysvwYLBDPZdRTIbVMCEwM=;\n b=eu3AnieSuuGxfHDqDHS063nFdFCnb4XVi+s+mv5RPKZlK8twfs1GoNefsW6nTzd3mz\n Xow0EeSy/lMfsdldkG92vHWI0zyiPQByt+P7IVt+KZ/9oVkR8pDS1tZYhi2MCEJTr6ct\n BnzG3ukzwKk37Ls5/EtOLtCq6/76oiJI7ANsf2kjspVX9xwjtnGx0pnm8otb1EkM+BNY\n KiJdVVDrrgLfZzM7oyEI0SmToBTOlZqJJJArH0TKhhMmzeCoFhJ2u5mfXNuUzpDPekFM\n yuUisyyor2hAoh38S66bTotrf0RLki42wW4IL7W46kdbEhx/g8KrlGRsy5+tnLqCkCe7\n Qp0Q==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20221208; t=1686428243; x=1689020243;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc\n :subject:date:message-id:reply-to;\n bh=kSxa0ZgoyozgWrQqCFL1esysvwYLBDPZdRTIbVMCEwM=;\n b=dLnGmJrceyFtf1ughfDb9DVHBPy5T/UBwF3rnbMnApz05O5hxP86aFF6jv4nxhkQXR\n zARmOn5wQjuCUY+W0zu16FW8l4MKRtI/7v5qPulStRpjoMPTdio2Btr6sPypV6TwThTJ\n IrGCVI30k4Yx9rg5kqnm/inDpoFYKI2ojSR/vg18djt57/qRJay4sNLcQSEWMxgW5Fnq\n RkXEGQquFRQdooBoxOb6sAJxBqpO+puRD33MyuTIW5ltr4vPTlaT9n/4ZyHx1h7hbLmF\n NaI2xsl5RzgQbKZsXCIZA2BGy59dKfiv4qIMw+6yYq8REvBpBQj4vy7s27uji9ysaeyw\n S0Tw==",
        "X-Gm-Message-State": "AC+VfDx6XB/VwQ3kNlbR9C81WpenTD1dQphUecUcAeAMHlYNEQ7E89Y7\n L1xIVk71VuX2sjP0QCrjbFs=",
        "X-Google-Smtp-Source": "\n ACHHUZ7zrvvWZzO3Z+T3FJJAB4I+QddyLVTyJuumtHHxrNcwFL9tQAZLVfeLlDzwjBgAlvGAfxnhfw==",
        "X-Received": "by 2002:a05:6a20:9383:b0:110:f65a:13d7 with SMTP id\n x3-20020a056a20938300b00110f65a13d7mr5869626pzh.9.1686428242753;\n Sat, 10 Jun 2023 13:17:22 -0700 (PDT)",
        "From": "Tanzeel-inline <tanxeel1.ahmed@gmail.com>",
        "To": "olivier.matz@6wind.com,\n\tthomas@monjalon.net,\n\ttanzeelahmed713@gmail.com",
        "Cc": "dev@dpdk.org,\n\tTanzeel-inline <tanxeel1.ahmed@gmail.com>",
        "Subject": "[PATCH v5] lib/net: add MPLS insert and strip functionality",
        "Date": "Sun, 11 Jun 2023 01:17:10 +0500",
        "Message-Id": "<20230610201710.929-1-tanxeel1.ahmed@gmail.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20230219224334.309-1-tanxeel1.ahmed@gmail.com>",
        "References": "<20230219224334.309-1-tanxeel1.ahmed@gmail.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": "None of the foundational NICs currently supports MPLS insertion and\nstripping, this functionality can help users who rely on MPLS in their\nnetwork application.\n\nSigned-off-by: Tanzeel Ahmed <tanxeel1.ahmed@gmail.com>\n\n---\n\nThis patch is new version of [PATCH] lib/net: added push MPLS header API.\nI have also added the MPLS strip functionality to address the question\nasked in last patch.\n\n> To be honest, I have some doubts about the usefulness of the patch,\n> especially the function that strips all the MPLS headers.\n\nI believe it serves a practical purpose, in scenarios involving tapped traffic where MPLS headers\nhave not been stripped.\nWhile some headers in the lib/net folder have well-defined functions, others are limited to their\nstructure alone. It would be advantageous to have basic functions available for all headers.\n\n> I think the function should only strip the first MPLS header, it is\n> symmetric with the previous function, and more flexible.\n\nYou are right, stripping one header is more flexible.\nI updated the function to return 1, in case of stripping last MPLS header.\n\nv5:\n* Updated the MPLS strip function to strip one header at a time.\n* Added the unit test cases.\n\nv4:\n* Removed extra void cast.\n* rte_pktmbuf_append/mtod now return void*.\n  The memmove result is casted to rte_ether_hdr*.\n\nv3:\n* fixed patch check failure issue\n\nv2:\n* marked experimental\n* coding style fixed\n* changed rte_memcpy to memcpy\n* mpls header marked as const in parameter\n* added MPLS stripping functionality\n---\n app/test/meson.build |   2 +\n app/test/test_mpls.c | 180 +++++++++++++++++++++++++++++++++++++++++++\n lib/net/rte_mpls.h   | 106 +++++++++++++++++++++++++\n 3 files changed, 288 insertions(+)\n create mode 100644 app/test/test_mpls.c",
    "diff": "diff --git a/app/test/meson.build b/app/test/meson.build\nindex f34d19e3c3..548349399f 100644\n--- a/app/test/meson.build\n+++ b/app/test/meson.build\n@@ -95,6 +95,7 @@ test_sources = files(\n         'test_meter.c',\n         'test_mcslock.c',\n         'test_mp_secondary.c',\n+        'test_mpls.c',\n         'test_per_lcore.c',\n         'test_pflock.c',\n         'test_pmd_perf.c',\n@@ -205,6 +206,7 @@ fast_tests = [\n         ['mempool_autotest', false, true],\n         ['memzone_autotest', false, true],\n         ['meter_autotest', true, true],\n+        ['mpls_autotest', false, true],\n         ['multiprocess_autotest', false, false],\n         ['per_lcore_autotest', true, true],\n         ['pflock_autotest', true, true],\ndiff --git a/app/test/test_mpls.c b/app/test/test_mpls.c\nnew file mode 100644\nindex 0000000000..8ff701f6e0\n--- /dev/null\n+++ b/app/test/test_mpls.c\n@@ -0,0 +1,180 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2010-2014 Intel Corporation\n+ */\n+\n+#include \"test.h\"\n+\n+#include <string.h>\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <stdint.h>\n+\n+#include <rte_common.h>\n+#include <rte_memory.h>\n+#include <rte_memcpy.h>\n+#include <rte_mbuf.h>\n+#include <rte_malloc.h>\n+#include <rte_ether.h>\n+#include <rte_mpls.h>\n+\n+#define MEMPOOL_CACHE_SIZE      32\n+#define MBUF_DATA_SIZE          2048\n+#define NB_MBUF                 128\n+\n+static int\n+test_mpls_fail_push(struct rte_mbuf *m)\n+{\n+\tstruct rte_mpls_hdr mpls;\n+\n+\t/* create dummy MPLS header */\n+\tmpls.tag_msb = 1;\n+\tmpls.tag_lsb = 2;\n+\tmpls.bs = 1;\n+\tmpls.tc = 1;\n+\tmpls.ttl = 255;\n+\n+\t/* push first MPLS header */\n+\tif (rte_mpls_push_over_l2(m, &mpls) != 0)\n+\t\treturn 0;\n+\treturn -1;\n+}\n+\n+static int\n+test_mpls_push(struct rte_mbuf *m)\n+{\n+\tstruct rte_mpls_hdr mpls;\n+\n+\t/* create dummy MPLS header */\n+\tmpls.tag_msb = 1;\n+\tmpls.tag_lsb = 2;\n+\tmpls.bs = 1;\n+\tmpls.tc = 1;\n+\tmpls.ttl = 255;\n+\n+\t/* push first MPLS header */\n+\tif (rte_mpls_push_over_l2(m, &mpls) != 0) {\n+\t\tprintf(\"Failed to insert mpls 1\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (rte_pktmbuf_pkt_len(m) != RTE_ETHER_HDR_LEN + RTE_MPLS_HLEN) {\n+\t\tprintf(\"Bad pkt length after inserting first mpls header\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\t/* push second MPLS header*/\n+\tif (rte_mpls_push_over_l2(m, &mpls) != 0) {\n+\t\tprintf(\"failed to insert mpls 1\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (rte_pktmbuf_pkt_len(m) != RTE_ETHER_HDR_LEN + RTE_MPLS_HLEN * 2) {\n+\t\tprintf(\"bad pkt length after inserting second mpls header\\n\");\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+test_mpls_fail_strip(struct rte_mbuf *m)\n+{\n+\t/* strip MPLS headers */\n+\tif (rte_mpls_strip_over_l2(m) != 0)\n+\t\treturn 0;\n+\treturn -1;\n+}\n+\n+static int\n+test_mpls_strip(struct rte_mbuf *m)\n+{\n+\t/* strip MPLS headers */\n+\treturn rte_mpls_strip_over_l2(m);\n+}\n+\n+static int\n+test_mpls(void)\n+{\n+\tint ret = -1;\n+\tstruct rte_mempool *pktmbuf_pool = NULL;\n+\tstruct rte_mbuf *m = NULL;\n+\tchar *data;\n+\tstruct rte_ether_hdr eh;\n+\n+\t/* create pktmbuf pool */\n+\tpktmbuf_pool = rte_pktmbuf_pool_create(\"test_mpls_pool\",\n+\t\t\tNB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,\n+\t\t\tSOCKET_ID_ANY);\n+\n+\tif (pktmbuf_pool == NULL) {\n+\t\tprintf(\"cannot allocate mbuf pool\\n\");\n+\t\tgoto err;\n+\t}\n+\n+    /* allocate mbuf from pool */\n+\tm = rte_pktmbuf_alloc(pktmbuf_pool);\n+\tif (m == NULL) {\n+\t\tprintf(\"mbuf alloc failed\\n\");\n+\t\tgoto err;\n+\t}\n+\tif (rte_pktmbuf_data_len(m) != 0) {\n+\t\tprintf(\"mbuf alloc bad length\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tif (test_mpls_fail_push(m) < 0) {\n+\t\tprintf(\"test_mpls_fail_push() failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tif (test_mpls_fail_strip(m) < 0) {\n+\t\tprintf(\"test_mpls_fail_strip() failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\t/* create a dummy ethernet header */\n+\tmemset(&eh.src_addr, 0, RTE_ETHER_ADDR_LEN);\n+\tmemset(&eh.dst_addr, 0, RTE_ETHER_ADDR_LEN);\n+\teh.ether_type = rte_be_to_cpu_16(RTE_ETHER_TYPE_IPV4);\n+\n+\t/* append ethernet header into mbuf */\n+\tdata = rte_pktmbuf_append(m, RTE_ETHER_HDR_LEN);\n+\tif (data == NULL) {\n+\t\tprintf(\"cannot append data\\n\");\n+\t\tgoto err;\n+\t}\n+\tif (rte_pktmbuf_data_len(m) != RTE_ETHER_HDR_LEN) {\n+\t\tprintf(\"bad pkt data length\\n\");\n+\t\tgoto err;\n+\t}\n+\tmemcpy(data, &eh, RTE_ETHER_HDR_LEN);\n+\n+\tif (test_mpls_push(m) < 0) {\n+\t\tprintf(\"test_mpls_push() failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tif (test_mpls_strip(m) < 0) {\n+\t\tprintf(\"test_mpls_push() failed\\n\");\n+\t\tgoto err;\n+\t}\n+\tif (rte_pktmbuf_data_len(m) != RTE_ETHER_HDR_LEN + RTE_MPLS_HLEN) {\n+\t\tprintf(\"bad pkt data length after stripping first MPLS header\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tif (test_mpls_strip(m) < 0) {\n+\t\tprintf(\"test_mpls_push() failed\\n\");\n+\t\tgoto err;\n+\t}\n+\tif (rte_pktmbuf_data_len(m) != RTE_ETHER_HDR_LEN) {\n+\t\tprintf(\"bad pkt data length after stripping second MPLS header\\n\");\n+\t\tgoto err;\n+\t}\n+\tret = 0;\n+err:\n+\tif (m)\n+\t\trte_pktmbuf_free(m);\n+\tif (pktmbuf_pool)\n+\t\trte_mempool_free(pktmbuf_pool);\n+\treturn ret;\n+}\n+\n+REGISTER_TEST_COMMAND(mpls_autotest, test_mpls);\ndiff --git a/lib/net/rte_mpls.h b/lib/net/rte_mpls.h\nindex 3e8cb90ec3..a2072cdd10 100644\n--- a/lib/net/rte_mpls.h\n+++ b/lib/net/rte_mpls.h\n@@ -13,6 +13,8 @@\n \n #include <stdint.h>\n #include <rte_byteorder.h>\n+#include <rte_ether.h>\n+#include <rte_mbuf.h>\n \n #ifdef __cplusplus\n extern \"C\" {\n@@ -36,6 +38,110 @@ struct rte_mpls_hdr {\n \tuint8_t  ttl;       /**< Time to live. */\n } __rte_packed;\n \n+#define RTE_MPLS_HLEN 4 /**< Length of MPLS header. */\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Insert MPLS header into the packet.\n+ * If it's the first MPLS header to be inserted in the packet,\n+ *  - Update the ether type.\n+ *  - Set the MPLS bottom-of-stack bit to 1.\n+ *\n+ * @param m\n+ *   The pointer to the mbuf.\n+ * @param mp\n+ *   The pointer to the MPLS header.\n+ * @return\n+ *   0 on success, -1 on error.\n+ */\n+__rte_experimental\n+static inline int\n+rte_mpls_push_over_l2(struct rte_mbuf *m, const struct rte_mpls_hdr *mp)\n+{\n+\tstruct rte_ether_hdr *oh, *nh;\n+\tstruct rte_mpls_hdr *mph;\n+\n+\t/* Can't insert header if mbuf is shared */\n+\tif (!RTE_MBUF_DIRECT(m) || rte_mbuf_refcnt_read(m) > 1)\n+\t\treturn -EINVAL;\n+\n+\t/* Can't insert header if ethernet frame doesn't exist */\n+\tif (rte_pktmbuf_data_len(m) < RTE_ETHER_HDR_LEN)\n+\t\treturn -EINVAL;\n+\n+\toh = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);\n+\tnh = (struct rte_ether_hdr *)(void *)\n+\t\trte_pktmbuf_prepend(m, sizeof(struct rte_mpls_hdr));\n+\tif (nh == NULL)\n+\t\treturn -ENOSPC;\n+\n+\tmemmove(nh, oh, RTE_ETHER_HDR_LEN);\n+\n+\t/* Copy the MPLS header after ethernet frame */\n+\tmph = rte_pktmbuf_mtod_offset(m, struct rte_mpls_hdr *,\n+\t\t\tsizeof(struct rte_ether_hdr));\n+\tmemcpy(mph, mp, RTE_MPLS_HLEN);\n+\n+\tmph->tag_msb = rte_cpu_to_be_16(mp->tag_msb);\n+\n+\t/* If first MPLS header, update ether type and bottom-of-stack bit */\n+\tif (nh->ether_type != rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLS)) {\n+\t\tnh->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLS);\n+\t\tmph->bs = 1;\n+\t} else {\n+\t\tmph->bs = 0;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Strip MPLS header from the packet without updating the ether type.\n+ *\n+ * @param m\n+ *   The pointer to the mbuf.\n+ * @return\n+ *   1 if last MPLS header is stripped,\n+ *   0 on success,\n+ *   -1 on error.\n+ */\n+__rte_experimental\n+static inline int\n+rte_mpls_strip_over_l2(struct rte_mbuf *m)\n+{\n+\tstruct rte_ether_hdr *eh = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);\n+\tstruct rte_mpls_hdr *mph;\n+\tint result = 0;\n+\n+\t/* Can't strip header if mbuf is shared */\n+\tif (!RTE_MBUF_DIRECT(m) || rte_mbuf_refcnt_read(m) > 1)\n+\t\treturn -EINVAL;\n+\n+\t/* Can't strip header if packet length is smaller */\n+\tif (rte_pktmbuf_data_len(m) < RTE_ETHER_HDR_LEN + RTE_MPLS_HLEN)\n+\t\treturn -EINVAL;\n+\n+\tif (eh->ether_type != rte_cpu_to_be_16(RTE_ETHER_TYPE_MPLS))\n+\t\treturn -1;\n+\n+\t/* Stripping MPLS header */\n+\tmph = rte_pktmbuf_mtod_offset(m, struct rte_mpls_hdr *,\n+\t\tsizeof(struct rte_ether_hdr));\n+\tif (mph->bs & 1)\n+\t\tresult = 1;\n+\tmemmove(\n+\t\trte_pktmbuf_adj(m, sizeof(struct rte_mpls_hdr)),\n+\t\teh, sizeof(struct rte_ether_hdr));\n+\teh = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);\n+\n+\treturn result;\n+}\n+\n #ifdef __cplusplus\n }\n #endif\n",
    "prefixes": [
        "v5"
    ]
}