get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 56287,
    "url": "http://patchwork.dpdk.org/api/patches/56287/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20190710092907.5565-1-olivier.matz@6wind.com/",
    "project": {
        "id": 1,
        "url": "http://patchwork.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": "<20190710092907.5565-1-olivier.matz@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20190710092907.5565-1-olivier.matz@6wind.com",
    "date": "2019-07-10T09:29:07",
    "name": "[RFC] mbuf: support dynamic fields and flags",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "9123dfe493dd838e5d1de9caef5ef49dcc2aa61d",
    "submitter": {
        "id": 8,
        "url": "http://patchwork.dpdk.org/api/people/8/?format=api",
        "name": "Olivier Matz",
        "email": "olivier.matz@6wind.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/20190710092907.5565-1-olivier.matz@6wind.com/mbox/",
    "series": [
        {
            "id": 5423,
            "url": "http://patchwork.dpdk.org/api/series/5423/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=5423",
            "date": "2019-07-10T09:29:07",
            "name": "[RFC] mbuf: support dynamic fields and flags",
            "version": 1,
            "mbox": "http://patchwork.dpdk.org/series/5423/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/56287/comments/",
    "check": "warning",
    "checks": "http://patchwork.dpdk.org/api/patches/56287/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 [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 75CEC2BF4;\n\tWed, 10 Jul 2019 11:29:18 +0200 (CEST)",
            "from proxy.6wind.com (host.76.145.23.62.rev.coltfrance.com\n\t[62.23.145.76]) by dpdk.org (Postfix) with ESMTP id D88852B99\n\tfor <dev@dpdk.org>; Wed, 10 Jul 2019 11:29:17 +0200 (CEST)",
            "from glumotte.dev.6wind.com. (unknown [10.16.0.195])\n\tby proxy.6wind.com (Postfix) with ESMTP id 9CC9F2E4383\n\tfor <dev@dpdk.org>; Wed, 10 Jul 2019 11:29:17 +0200 (CEST)"
        ],
        "From": "Olivier Matz <olivier.matz@6wind.com>",
        "To": "dev@dpdk.org",
        "Date": "Wed, 10 Jul 2019 11:29:07 +0200",
        "Message-Id": "<20190710092907.5565-1-olivier.matz@6wind.com>",
        "X-Mailer": "git-send-email 2.11.0",
        "Subject": "[dpdk-dev] [RFC] mbuf: support dynamic fields and flags",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<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\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Many features require to store data inside the mbuf. As the room in mbuf\nstructure is limited, it is not possible to have a field for each\nfeature. Also, changing fields in the mbuf structure can break the API\nor ABI.\n\nThis commit addresses these issues, by enabling the dynamic registration\nof fields or flags:\n\n- a dynamic field is a named area in the rte_mbuf structure, with a\n  given size (>= 1 byte) and alignment constraint.\n- a dynamic flag is a named bit in the rte_mbuf structure.\n\nThe typical use case is a PMD that registers space for an offload\nfeature, when the application requests to enable this feature.  As\nthe space in mbuf is limited, the space should only be reserved if it\nis going to be used (i.e when the application explicitly asks for it).\n\nThe registration can be done at any moment, but it is not possible\nto unregister fields or flags for now.\n\nSigned-off-by: Olivier Matz <olivier.matz@6wind.com>\n---\n app/test/test_mbuf.c                 |  83 +++++++-\n lib/librte_mbuf/Makefile             |   2 +\n lib/librte_mbuf/meson.build          |   6 +-\n lib/librte_mbuf/rte_mbuf.h           |  25 ++-\n lib/librte_mbuf/rte_mbuf_dyn.c       | 373 +++++++++++++++++++++++++++++++++++\n lib/librte_mbuf/rte_mbuf_dyn.h       | 119 +++++++++++\n lib/librte_mbuf/rte_mbuf_version.map |   4 +\n 7 files changed, 607 insertions(+), 5 deletions(-)\n create mode 100644 lib/librte_mbuf/rte_mbuf_dyn.c\n create mode 100644 lib/librte_mbuf/rte_mbuf_dyn.h",
    "diff": "diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c\nindex 2a97afe20..8008cc766 100644\n--- a/app/test/test_mbuf.c\n+++ b/app/test/test_mbuf.c\n@@ -28,6 +28,7 @@\n #include <rte_random.h>\n #include <rte_cycles.h>\n #include <rte_malloc.h>\n+#include <rte_mbuf_dyn.h>\n \n #include \"test.h\"\n \n@@ -502,7 +503,6 @@ test_attach_from_different_pool(struct rte_mempool *pktmbuf_pool,\n \t\trte_pktmbuf_free(clone2);\n \treturn -1;\n }\n-#undef GOTO_FAIL\n \n /*\n  * test allocation and free of mbufs\n@@ -1122,6 +1122,81 @@ test_tx_offload(void)\n }\n \n static int\n+test_mbuf_dyn(struct rte_mempool *pktmbuf_pool)\n+{\n+\tstruct rte_mbuf *m = NULL;\n+\tint offset, offset2;\n+\tint flag, flag2;\n+\n+\toffset = rte_mbuf_dynfield_register(\"test-dynfield\", sizeof(uint8_t),\n+\t\t\t\t\t__alignof__(uint8_t), 0);\n+\tif (offset == -1)\n+\t\tGOTO_FAIL(\"failed to register dynamic field, offset=%d: %s\",\n+\t\t\toffset, strerror(errno));\n+\n+\toffset2 = rte_mbuf_dynfield_register(\"test-dynfield\", sizeof(uint8_t),\n+\t\t\t\t\t__alignof__(uint8_t), 0);\n+\tif (offset2 != offset)\n+\t\tGOTO_FAIL(\"failed to lookup dynamic field, offset=%d, offset2=%d: %s\",\n+\t\t\toffset, offset2, strerror(errno));\n+\n+\toffset2 = rte_mbuf_dynfield_register(\"test-dynfield2\", sizeof(uint16_t),\n+\t\t\t\t\t__alignof__(uint16_t), 0);\n+\tif (offset2 == -1 || offset2 == offset || (offset & 1))\n+\t\tGOTO_FAIL(\"failed to register dynfield field 2, offset=%d, offset2=%d: %s\",\n+\t\t\toffset, offset2, strerror(errno));\n+\n+\tprintf(\"offset = %d, offset2 = %d\\n\", offset, offset2);\n+\n+\toffset = rte_mbuf_dynfield_register(\"test-dynfield-fail\", 256, 1, 0);\n+\tif (offset != -1)\n+\t\tGOTO_FAIL(\"dynamic field creation should fail (too big)\");\n+\n+\toffset = rte_mbuf_dynfield_register(\"test-dynfield-fail\", 1, 3, 0);\n+\tif (offset != -1)\n+\t\tGOTO_FAIL(\"dynamic field creation should fail (bad alignment)\");\n+\n+\tflag = rte_mbuf_dynflag_register(\"test-dynflag\");\n+\tif (flag == -1)\n+\t\tGOTO_FAIL(\"failed to register dynamic field, flag=%d: %s\",\n+\t\t\tflag, strerror(errno));\n+\n+\tflag2 = rte_mbuf_dynflag_register(\"test-dynflag\");\n+\tif (flag2 != flag)\n+\t\tGOTO_FAIL(\"failed to lookup dynamic field, flag=%d, flag2=%d: %s\",\n+\t\t\tflag, flag2, strerror(errno));\n+\n+\tflag2 = rte_mbuf_dynflag_register(\"test-dynflag2\");\n+\tif (flag2 == -1 || flag2 == flag)\n+\t\tGOTO_FAIL(\"failed to register dynflag field 2, flag=%d, flag2=%d: %s\",\n+\t\t\tflag, flag2, strerror(errno));\n+\n+\tprintf(\"flag = %d, flag2 = %d\\n\", flag, flag2);\n+\n+\t/* set, get dynamic field */\n+\tm = rte_pktmbuf_alloc(pktmbuf_pool);\n+\tif (m == NULL)\n+\t\tGOTO_FAIL(\"Cannot allocate mbuf\");\n+\n+\t*RTE_MBUF_DYNFIELD(m, offset, uint8_t *) = 1;\n+\tif (*RTE_MBUF_DYNFIELD(m, offset, uint8_t *) != 1)\n+\t\tGOTO_FAIL(\"failed to read dynamic field\");\n+\t*RTE_MBUF_DYNFIELD(m, offset2, uint16_t *) = 1000;\n+\tif (*RTE_MBUF_DYNFIELD(m, offset2, uint16_t *) != 1000)\n+\t\tGOTO_FAIL(\"failed to read dynamic field\");\n+\n+\t/* set a dynamic flag */\n+\tm->ol_flags |= (1ULL << flag);\n+\n+\trte_pktmbuf_free(m);\n+\treturn 0;\n+fail:\n+\trte_pktmbuf_free(m);\n+\treturn -1;\n+}\n+#undef GOTO_FAIL\n+\n+static int\n test_mbuf(void)\n {\n \tint ret = -1;\n@@ -1140,6 +1215,12 @@ test_mbuf(void)\n \t\tgoto err;\n \t}\n \n+\t/* test registration of dynamic fields and flags */\n+\tif (test_mbuf_dyn(pktmbuf_pool) < 0) {\n+\t\tprintf(\"mbuf dynflag test failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n \t/* create a specific pktmbuf pool with a priv_size != 0 and no data\n \t * room size */\n \tpktmbuf_pool2 = rte_pktmbuf_pool_create(\"test_pktmbuf_pool2\",\ndiff --git a/lib/librte_mbuf/Makefile b/lib/librte_mbuf/Makefile\nindex c8f6d2689..5a9bcee73 100644\n--- a/lib/librte_mbuf/Makefile\n+++ b/lib/librte_mbuf/Makefile\n@@ -17,8 +17,10 @@ LIBABIVER := 5\n \n # all source are stored in SRCS-y\n SRCS-$(CONFIG_RTE_LIBRTE_MBUF) := rte_mbuf.c rte_mbuf_ptype.c rte_mbuf_pool_ops.c\n+SRCS-$(CONFIG_RTE_LIBRTE_MBUF) += rte_mbuf_dyn.c\n \n # install includes\n SYMLINK-$(CONFIG_RTE_LIBRTE_MBUF)-include := rte_mbuf.h rte_mbuf_ptype.h rte_mbuf_pool_ops.h\n+SYMLINK-$(CONFIG_RTE_LIBRTE_MBUF)-include += rte_mbuf_dyn.h\n \n include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/lib/librte_mbuf/meson.build b/lib/librte_mbuf/meson.build\nindex 6cc11ebb4..9137e8f26 100644\n--- a/lib/librte_mbuf/meson.build\n+++ b/lib/librte_mbuf/meson.build\n@@ -2,8 +2,10 @@\n # Copyright(c) 2017 Intel Corporation\n \n version = 5\n-sources = files('rte_mbuf.c', 'rte_mbuf_ptype.c', 'rte_mbuf_pool_ops.c')\n-headers = files('rte_mbuf.h', 'rte_mbuf_ptype.h', 'rte_mbuf_pool_ops.h')\n+sources = files('rte_mbuf.c', 'rte_mbuf_ptype.c', 'rte_mbuf_pool_ops.c',\n+\t'rte_mbuf_dyn.c')\n+headers = files('rte_mbuf.h', 'rte_mbuf_ptype.h', 'rte_mbuf_pool_ops.h',\n+\t'rte_mbuf_dyn.h')\n deps += ['mempool']\n \n allow_experimental_apis = true\ndiff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h\nindex 98225ec80..ef588cd54 100644\n--- a/lib/librte_mbuf/rte_mbuf.h\n+++ b/lib/librte_mbuf/rte_mbuf.h\n@@ -198,9 +198,12 @@ extern \"C\" {\n #define PKT_RX_OUTER_L4_CKSUM_GOOD\t(1ULL << 22)\n #define PKT_RX_OUTER_L4_CKSUM_INVALID\t((1ULL << 21) | (1ULL << 22))\n \n-/* add new RX flags here */\n+/* add new RX flags here, don't forget to update PKT_FIRST_FREE */\n \n-/* add new TX flags here */\n+#define PKT_FIRST_FREE (1ULL << 23)\n+#define PKT_LAST_FREE (1ULL << 39)\n+\n+/* add new TX flags here, don't forget to update PKT_LAST_FREE  */\n \n /**\n  * Indicate that the metadata field in the mbuf is in use.\n@@ -738,6 +741,8 @@ struct rte_mbuf {\n \t */\n \tstruct rte_mbuf_ext_shared_info *shinfo;\n \n+\tuint64_t dynfield1; /**< Reserved for dynamic fields. */\n+\tuint64_t dynfield2; /**< Reserved for dynamic fields. */\n } __rte_cache_aligned;\n \n /**\n@@ -1685,6 +1690,21 @@ rte_pktmbuf_attach_extbuf(struct rte_mbuf *m, void *buf_addr,\n #define rte_pktmbuf_detach_extbuf(m) rte_pktmbuf_detach(m)\n \n /**\n+ * Copy dynamic fields from m_src to m_dst.\n+ *\n+ * @param m_dst\n+ *   The destination mbuf.\n+ * @param m_src\n+ *   The source mbuf.\n+ */\n+static inline void\n+rte_mbuf_dynfield_copy(struct rte_mbuf *m_dst, const struct rte_mbuf *m_src)\n+{\n+\tm_dst->dynfield1 = m_src->dynfield1;\n+\tm_dst->dynfield2 = m_src->dynfield2;\n+}\n+\n+/**\n  * Attach packet mbuf to another packet mbuf.\n  *\n  * If the mbuf we are attaching to isn't a direct buffer and is attached to\n@@ -1732,6 +1752,7 @@ static inline void rte_pktmbuf_attach(struct rte_mbuf *mi, struct rte_mbuf *m)\n \tmi->vlan_tci_outer = m->vlan_tci_outer;\n \tmi->tx_offload = m->tx_offload;\n \tmi->hash = m->hash;\n+\trte_mbuf_dynfield_copy(mi, m);\n \n \tmi->next = NULL;\n \tmi->pkt_len = mi->data_len;\ndiff --git a/lib/librte_mbuf/rte_mbuf_dyn.c b/lib/librte_mbuf/rte_mbuf_dyn.c\nnew file mode 100644\nindex 000000000..6a96a43da\n--- /dev/null\n+++ b/lib/librte_mbuf/rte_mbuf_dyn.c\n@@ -0,0 +1,373 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2019 6WIND S.A.\n+ */\n+\n+#include <sys/queue.h>\n+\n+#include <rte_common.h>\n+#include <rte_eal.h>\n+#include <rte_eal_memconfig.h>\n+#include <rte_tailq.h>\n+#include <rte_errno.h>\n+#include <rte_malloc.h>\n+#include <rte_string_fns.h>\n+#include <rte_mbuf.h>\n+#include <rte_mbuf_dyn.h>\n+\n+#define RTE_MBUF_DYN_MZNAME \"rte_mbuf_dyn\"\n+\n+struct mbuf_dynfield {\n+\tTAILQ_ENTRY(mbuf_dynfield) next;\n+\tchar name[RTE_MBUF_DYN_NAMESIZE];\n+\tsize_t size;\n+\tsize_t align;\n+\tunsigned int flags;\n+\tint offset;\n+};\n+TAILQ_HEAD(mbuf_dynfield_list, rte_tailq_entry);\n+\n+static struct rte_tailq_elem mbuf_dynfield_tailq = {\n+\t.name = \"RTE_MBUF_DYNFIELD\",\n+};\n+EAL_REGISTER_TAILQ(mbuf_dynfield_tailq);\n+\n+struct mbuf_dynflag {\n+\tTAILQ_ENTRY(mbuf_dynflag) next;\n+\tchar name[RTE_MBUF_DYN_NAMESIZE];\n+\tint bitnum;\n+};\n+TAILQ_HEAD(mbuf_dynflag_list, rte_tailq_entry);\n+\n+static struct rte_tailq_elem mbuf_dynflag_tailq = {\n+\t.name = \"RTE_MBUF_DYNFLAG\",\n+};\n+EAL_REGISTER_TAILQ(mbuf_dynflag_tailq);\n+\n+struct mbuf_dyn_shm {\n+\t/** For each mbuf byte, free_space[i] == 1 if space is free. */\n+\tuint8_t free_space[sizeof(struct rte_mbuf)];\n+\t/** Bitfield of available flags. */\n+\tuint64_t free_flags;\n+};\n+static struct mbuf_dyn_shm *shm;\n+\n+/* allocate and initialize the shared memory */\n+static int\n+init_shared_mem(void)\n+{\n+\tconst struct rte_memzone *mz;\n+\tuint64_t mask;\n+\n+\tif (rte_eal_process_type() == RTE_PROC_PRIMARY) {\n+\t\tmz = rte_memzone_reserve_aligned(RTE_MBUF_DYN_MZNAME,\n+\t\t\t\t\t\tsizeof(struct mbuf_dyn_shm),\n+\t\t\t\t\t\tSOCKET_ID_ANY, 0,\n+\t\t\t\t\t\tRTE_CACHE_LINE_SIZE);\n+\t} else {\n+\t\tmz = rte_memzone_lookup(RTE_MBUF_DYN_MZNAME);\n+\t}\n+\tif (mz == NULL)\n+\t\treturn -1;\n+\n+\tshm = mz->addr;\n+\n+#define mark_free(field)\t\t\t\t\t\t\\\n+\tmemset(&shm->free_space[offsetof(struct rte_mbuf, field)],\t\\\n+\t\t0xff, sizeof(((struct rte_mbuf *)0)->field))\n+\n+\tif (rte_eal_process_type() == RTE_PROC_PRIMARY) {\n+\t\t/* init free_space, keep it sync'd with\n+\t\t * rte_mbuf_dynfield_copy().\n+\t\t */\n+\t\tmemset(shm, 0, sizeof(*shm));\n+\t\tmark_free(dynfield1);\n+\t\tmark_free(dynfield2);\n+\n+\t\t/* init free_flags */\n+\t\tfor (mask = PKT_FIRST_FREE; mask <= PKT_LAST_FREE; mask <<= 1)\n+\t\t\tshm->free_flags |= mask;\n+\t}\n+#undef mark_free\n+\n+\treturn 0;\n+}\n+\n+/* check if this offset can be used */\n+static int\n+check_offset(size_t offset, size_t size, size_t align, unsigned int flags)\n+{\n+\tsize_t i;\n+\n+\t(void)flags;\n+\n+\tif ((offset & (align - 1)) != 0)\n+\t\treturn -1;\n+\tif (offset + size > sizeof(struct rte_mbuf))\n+\t\treturn -1;\n+\n+\tfor (i = 0; i < size; i++) {\n+\t\tif (!shm->free_space[i + offset])\n+\t\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* assume tailq is locked */\n+static struct mbuf_dynfield *\n+__mbuf_dynfield_lookup(const char *name)\n+{\n+\tstruct mbuf_dynfield_list *mbuf_dynfield_list;\n+\tstruct mbuf_dynfield *mbuf_dynfield;\n+\tstruct rte_tailq_entry *te;\n+\n+\tmbuf_dynfield_list = RTE_TAILQ_CAST(\n+\t\tmbuf_dynfield_tailq.head, mbuf_dynfield_list);\n+\n+\tTAILQ_FOREACH(te, mbuf_dynfield_list, next) {\n+\t\tmbuf_dynfield = (struct mbuf_dynfield *)te->data;\n+\t\tif (strncmp(name, mbuf_dynfield->name,\n+\t\t\t\tRTE_MBUF_DYN_NAMESIZE) == 0)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (te == NULL) {\n+\t\trte_errno = ENOENT;\n+\t\treturn NULL;\n+\t}\n+\n+\treturn mbuf_dynfield;\n+}\n+\n+int\n+rte_mbuf_dynfield_lookup(const char *name, size_t *size, size_t *align)\n+{\n+\tstruct mbuf_dynfield *mbuf_dynfield;\n+\n+\tif (shm == NULL) {\n+\t\trte_errno = ENOENT;\n+\t\treturn -1;\n+\t}\n+\n+\trte_mcfg_tailq_read_lock();\n+\tmbuf_dynfield = __mbuf_dynfield_lookup(name);\n+\trte_mcfg_tailq_read_unlock();\n+\n+\tif (mbuf_dynfield == NULL) {\n+\t\trte_errno = ENOENT;\n+\t\treturn -1;\n+\t}\n+\n+\tif (size != NULL)\n+\t\t*size = mbuf_dynfield->size;\n+\tif (align != NULL)\n+\t\t*align = mbuf_dynfield->align;\n+\n+\treturn mbuf_dynfield->offset;\n+}\n+\n+int\n+rte_mbuf_dynfield_register(const char *name, size_t size, size_t align,\n+\t\t\tunsigned int flags)\n+{\n+\tstruct mbuf_dynfield_list *mbuf_dynfield_list;\n+\tstruct mbuf_dynfield *mbuf_dynfield = NULL;\n+\tstruct rte_tailq_entry *te = NULL;\n+\tint offset, ret;\n+\tsize_t i;\n+\n+\tif (shm == NULL && init_shared_mem() < 0)\n+\t\tgoto fail;\n+\tif (size >= sizeof(struct rte_mbuf)) {\n+\t\trte_errno = EINVAL;\n+\t\tgoto fail;\n+\t}\n+\tif (!rte_is_power_of_2(align)) {\n+\t\trte_errno = EINVAL;\n+\t\tgoto fail;\n+\t}\n+\n+\trte_mcfg_tailq_write_lock();\n+\n+\tmbuf_dynfield = __mbuf_dynfield_lookup(name);\n+\tif (mbuf_dynfield != NULL) {\n+\t\tif (mbuf_dynfield->size != size ||\n+\t\t\t\tmbuf_dynfield->align != align ||\n+\t\t\t\tmbuf_dynfield->flags != flags) {\n+\t\t\trte_errno = EEXIST;\n+\t\t\tgoto fail_unlock;\n+\t\t}\n+\t\toffset = mbuf_dynfield->offset;\n+\t\tgoto out_unlock;\n+\t}\n+\n+\tif (rte_eal_process_type() != RTE_PROC_PRIMARY) {\n+\t\trte_errno = EPERM;\n+\t\tgoto fail_unlock;\n+\t}\n+\n+\tfor (offset = 0;\n+\t     offset < (int)sizeof(struct rte_mbuf);\n+\t     offset++) {\n+\t\tif (check_offset(offset, size, align, flags) == 0)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (offset == sizeof(struct rte_mbuf)) {\n+\t\trte_errno = ENOENT;\n+\t\tgoto fail_unlock;\n+\t}\n+\n+\tmbuf_dynfield_list = RTE_TAILQ_CAST(\n+\t\tmbuf_dynfield_tailq.head, mbuf_dynfield_list);\n+\n+\tte = rte_zmalloc(\"MBUF_DYNFIELD_TAILQ_ENTRY\", sizeof(*te), 0);\n+\tif (te == NULL)\n+\t\tgoto fail_unlock;\n+\n+\tmbuf_dynfield = rte_zmalloc(\"mbuf_dynfield\", sizeof(*mbuf_dynfield), 0);\n+\tif (mbuf_dynfield == NULL)\n+\t\tgoto fail_unlock;\n+\n+\tret = strlcpy(mbuf_dynfield->name, name, sizeof(mbuf_dynfield->name));\n+\tif (ret < 0 || ret >= (int)sizeof(mbuf_dynfield->name)) {\n+\t\trte_errno = ENAMETOOLONG;\n+\t\tgoto fail_unlock;\n+\t}\n+\tmbuf_dynfield->size = size;\n+\tmbuf_dynfield->align = align;\n+\tmbuf_dynfield->flags = flags;\n+\tmbuf_dynfield->offset = offset;\n+\tte->data = mbuf_dynfield;\n+\n+\tTAILQ_INSERT_TAIL(mbuf_dynfield_list, te, next);\n+\n+\tfor (i = offset; i < offset + size; i++)\n+\t\tshm->free_space[i] = 0;\n+\n+out_unlock:\n+\trte_mcfg_tailq_write_unlock();\n+\n+\treturn offset;\n+\n+fail_unlock:\n+\trte_mcfg_tailq_write_unlock();\n+fail:\n+\trte_free(mbuf_dynfield);\n+\trte_free(te);\n+\treturn -1;\n+}\n+\n+/* assume tailq is locked */\n+static struct mbuf_dynflag *\n+__mbuf_dynflag_lookup(const char *name)\n+{\n+\tstruct mbuf_dynflag_list *mbuf_dynflag_list;\n+\tstruct mbuf_dynflag *mbuf_dynflag;\n+\tstruct rte_tailq_entry *te;\n+\n+\tmbuf_dynflag_list = RTE_TAILQ_CAST(\n+\t\tmbuf_dynflag_tailq.head, mbuf_dynflag_list);\n+\n+\tTAILQ_FOREACH(te, mbuf_dynflag_list, next) {\n+\t\tmbuf_dynflag = (struct mbuf_dynflag *)te->data;\n+\t\tif (strncmp(name, mbuf_dynflag->name,\n+\t\t\t\tRTE_MBUF_DYN_NAMESIZE) == 0)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (te == NULL) {\n+\t\trte_errno = ENOENT;\n+\t\treturn NULL;\n+\t}\n+\n+\treturn mbuf_dynflag;\n+}\n+\n+int\n+rte_mbuf_dynflag_lookup(const char *name)\n+{\n+\tstruct mbuf_dynflag *mbuf_dynflag;\n+\n+\tif (shm == NULL) {\n+\t\trte_errno = ENOENT;\n+\t\treturn -1;\n+\t}\n+\n+\trte_mcfg_tailq_read_lock();\n+\tmbuf_dynflag = __mbuf_dynflag_lookup(name);\n+\trte_mcfg_tailq_read_unlock();\n+\n+\tif (mbuf_dynflag == NULL) {\n+\t\trte_errno = ENOENT;\n+\t\treturn -1;\n+\t}\n+\n+\treturn mbuf_dynflag->bitnum;\n+}\n+\n+int\n+rte_mbuf_dynflag_register(const char *name)\n+{\n+\tstruct mbuf_dynflag_list *mbuf_dynflag_list;\n+\tstruct mbuf_dynflag *mbuf_dynflag = NULL;\n+\tstruct rte_tailq_entry *te = NULL;\n+\tint bitnum, ret;\n+\n+\tif (shm == NULL && init_shared_mem() < 0)\n+\t\tgoto fail;\n+\n+\trte_mcfg_tailq_write_lock();\n+\n+\tmbuf_dynflag = __mbuf_dynflag_lookup(name);\n+\tif (mbuf_dynflag != NULL) {\n+\t\tbitnum = mbuf_dynflag->bitnum;\n+\t\tgoto out_unlock;\n+\t}\n+\n+\tif (rte_eal_process_type() != RTE_PROC_PRIMARY) {\n+\t\trte_errno = EPERM;\n+\t\tgoto fail_unlock;\n+\t}\n+\n+\tif (shm->free_flags == 0) {\n+\t\trte_errno = ENOENT;\n+\t\tgoto fail_unlock;\n+\t}\n+\tbitnum = rte_bsf64(shm->free_flags);\n+\n+\tmbuf_dynflag_list = RTE_TAILQ_CAST(\n+\t\tmbuf_dynflag_tailq.head, mbuf_dynflag_list);\n+\n+\tte = rte_zmalloc(\"MBUF_DYNFLAG_TAILQ_ENTRY\", sizeof(*te), 0);\n+\tif (te == NULL)\n+\t\tgoto fail_unlock;\n+\n+\tmbuf_dynflag = rte_zmalloc(\"mbuf_dynflag\", sizeof(*mbuf_dynflag), 0);\n+\tif (mbuf_dynflag == NULL)\n+\t\tgoto fail_unlock;\n+\n+\tret = strlcpy(mbuf_dynflag->name, name, sizeof(mbuf_dynflag->name));\n+\tif (ret < 0 || ret >= (int)sizeof(mbuf_dynflag->name)) {\n+\t\trte_errno = ENAMETOOLONG;\n+\t\tgoto fail_unlock;\n+\t}\n+\tmbuf_dynflag->bitnum = bitnum;\n+\tte->data = mbuf_dynflag;\n+\n+\tTAILQ_INSERT_TAIL(mbuf_dynflag_list, te, next);\n+\n+\tshm->free_flags &= ~(1ULL << bitnum);\n+\n+out_unlock:\n+\trte_mcfg_tailq_write_unlock();\n+\n+\treturn bitnum;\n+\n+fail_unlock:\n+\trte_mcfg_tailq_write_unlock();\n+fail:\n+\trte_free(mbuf_dynflag);\n+\trte_free(te);\n+\treturn -1;\n+}\ndiff --git a/lib/librte_mbuf/rte_mbuf_dyn.h b/lib/librte_mbuf/rte_mbuf_dyn.h\nnew file mode 100644\nindex 000000000..a86986a0f\n--- /dev/null\n+++ b/lib/librte_mbuf/rte_mbuf_dyn.h\n@@ -0,0 +1,119 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2019 6WIND S.A.\n+ */\n+\n+#ifndef _RTE_MBUF_DYN_H_\n+#define _RTE_MBUF_DYN_H_\n+\n+/**\n+ * @file\n+ * RTE Mbuf dynamic fields and flags\n+ *\n+ * Many features require to store data inside the mbuf. As the room in\n+ * mbuf structure is limited, it is not possible to have a field for\n+ * each feature. Also, changing fields in the mbuf structure can break\n+ * the API or ABI.\n+ *\n+ * This module addresses this issue, by enabling the dynamic\n+ * registration of fields or flags:\n+ *\n+ * - a dynamic field is a named area in the rte_mbuf structure, with a\n+ *   given size (>= 1 byte) and alignment constraint.\n+ * - a dynamic flag is a named bit in the rte_mbuf structure.\n+ *\n+ * The typical use case is a PMD that registers space for an offload\n+ * feature, when the application requests to enable this feature.  As\n+ * the space in mbuf is limited, the space should only be reserved if it\n+ * is going to be used (i.e when the application explicitly asks for it).\n+ *\n+ * The registration can be done at any moment, but it is not possible\n+ * to unregister fields or flags for now.\n+ *\n+ * Example of use:\n+ *\n+ * - RTE_MBUF_DYN_<feature>_(ID|SIZE|ALIGN) are defined in this file\n+ * - If the application asks for the feature, the PMD use\n+ *   rte_mbuf_dynfield_register() to get the dynamic offset and stores\n+ *   in a global variable.\n+ * - The application also calls rte_mbuf_dynfield_register() to get the\n+ *   dynamic offset and stores it in a global variable.\n+ * - When the field must be used by the PMD or the application, they\n+ *   use the RTE_MBUF_DYNFIELD() helper.\n+ */\n+\n+struct rte_mbuf;\n+\n+/**\n+ * Register space for a dynamic field in the mbuf structure.\n+ *\n+ * @param name\n+ *   A string identifying the dynamic field. External applications or\n+ *   libraries must not define identifers prefixed with \"rte_\", which\n+ *   are reserved for standard features.\n+ * @param size\n+ *   The number of bytes to reserve.\n+ * @param align\n+ *   The alignment constraint, which must be a power of 2.\n+ * @param flags\n+ *   Reserved for future use.\n+ * @return\n+ *   The offset in the mbuf structure, or -1 on error (rte_errno is set).\n+ */\n+__rte_experimental\n+int rte_mbuf_dynfield_register(const char *name, size_t size, size_t align,\n+\t\t\tunsigned int flags);\n+\n+/**\n+ * Lookup for a registered dynamic mbuf field.\n+ *\n+ * @param name\n+ *   A string identifying the dynamic field.\n+ * @param size\n+ *   If not NULL, the number of reserved bytes for this field is stored\n+ *   at this address.\n+ * @param align\n+ *   If not NULL, the alignement constraint for this field is stored\n+ *   at this address.\n+ * @return\n+ *   The offset of this field in the mbuf structure, or -1 on error\n+ *   (rte_errno is set).\n+ */\n+__rte_experimental\n+int rte_mbuf_dynfield_lookup(const char *name, size_t *size, size_t *align);\n+\n+/**\n+ * Register a dynamic flag in the mbuf structure.\n+ *\n+ * @param name\n+ *   A string identifying the dynamic flag. External applications or\n+ *   libraries must not define identifers prefixed with \"rte_\", which\n+ *   are reserved for standard features.\n+ * @return\n+ *   The number of the reserved bit, or -1 on error (rte_errno is set).\n+ */\n+__rte_experimental\n+int rte_mbuf_dynflag_register(const char *name);\n+\n+/**\n+ * Lookup for a registered dynamic mbuf flag.\n+ *\n+ * @param name\n+ *   A string identifying the dynamic flag.\n+ * @return\n+ *   The offset of this flag in the mbuf structure, or -1 on error\n+ *   (rte_errno is set).\n+ */\n+__rte_experimental\n+int rte_mbuf_dynflag_lookup(const char *name);\n+\n+/**\n+ * Helper macro to access to a dynamic field.\n+ */\n+#define RTE_MBUF_DYNFIELD(m, offset, type) ((type)((char *)(m) + (offset)))\n+\n+/**\n+ * Maximum length of the dynamic field or flag string.\n+ */\n+#define RTE_MBUF_DYN_NAMESIZE 32\n+\n+#endif\ndiff --git a/lib/librte_mbuf/rte_mbuf_version.map b/lib/librte_mbuf/rte_mbuf_version.map\nindex 2662a37bf..a98310570 100644\n--- a/lib/librte_mbuf/rte_mbuf_version.map\n+++ b/lib/librte_mbuf/rte_mbuf_version.map\n@@ -50,4 +50,8 @@ EXPERIMENTAL {\n \tglobal:\n \n \trte_mbuf_check;\n+\trte_mbuf_dynfield_lookup;\n+\trte_mbuf_dynfield_register;\n+\trte_mbuf_dynflag_lookup;\n+\trte_mbuf_dynflag_register;\n } DPDK_18.08;\n",
    "prefixes": [
        "RFC"
    ]
}