get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 64989,
    "url": "http://patches.dpdk.org/api/patches/64989/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1579547786-7650-4-git-send-email-viacheslavo@mellanox.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": "<1579547786-7650-4-git-send-email-viacheslavo@mellanox.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1579547786-7650-4-git-send-email-viacheslavo@mellanox.com",
    "date": "2020-01-20T19:16:24",
    "name": "[v6,3/5] mbuf: create packet pool with external memory buffers",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "bd03000b6a65bc0f6e576c2c060a575b0aadb978",
    "submitter": {
        "id": 1102,
        "url": "http://patches.dpdk.org/api/people/1102/?format=api",
        "name": "Slava Ovsiienko",
        "email": "viacheslavo@mellanox.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/1579547786-7650-4-git-send-email-viacheslavo@mellanox.com/mbox/",
    "series": [
        {
            "id": 8228,
            "url": "http://patches.dpdk.org/api/series/8228/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=8228",
            "date": "2020-01-20T19:16:22",
            "name": "mbuf: detach mbuf with pinned external buffer",
            "version": 6,
            "mbox": "http://patches.dpdk.org/series/8228/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/64989/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/64989/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 dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 18E2DA0528;\n\tMon, 20 Jan 2020 20:17:01 +0100 (CET)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id E4AE41C0D0;\n\tMon, 20 Jan 2020 20:16:43 +0100 (CET)",
            "from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129])\n by dpdk.org (Postfix) with ESMTP id 6DAC91C0C1\n for <dev@dpdk.org>; Mon, 20 Jan 2020 20:16:40 +0100 (CET)",
            "from Internal Mail-Server by MTLPINE1 (envelope-from\n viacheslavo@mellanox.com)\n with ESMTPS (AES256-SHA encrypted); 20 Jan 2020 21:16:37 +0200",
            "from pegasus11.mtr.labs.mlnx (pegasus11.mtr.labs.mlnx\n [10.210.16.104])\n by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 00KJGbZ0019040;\n Mon, 20 Jan 2020 21:16:37 +0200",
            "from pegasus11.mtr.labs.mlnx (localhost [127.0.0.1])\n by pegasus11.mtr.labs.mlnx (8.14.7/8.14.7) with ESMTP id 00KJGamk007925;\n Mon, 20 Jan 2020 19:16:36 GMT",
            "(from viacheslavo@localhost)\n by pegasus11.mtr.labs.mlnx (8.14.7/8.14.7/Submit) id 00KJGaQ1007924;\n Mon, 20 Jan 2020 19:16:36 GMT"
        ],
        "X-Authentication-Warning": "pegasus11.mtr.labs.mlnx: viacheslavo set sender to\n viacheslavo@mellanox.com using -f",
        "From": "Viacheslav Ovsiienko <viacheslavo@mellanox.com>",
        "To": "dev@dpdk.org",
        "Cc": "matan@mellanox.com, rasland@mellanox.com, orika@mellanox.com,\n shahafs@mellanox.com, olivier.matz@6wind.com,\n stephen@networkplumber.org, thomas@mellanox.net",
        "Date": "Mon, 20 Jan 2020 19:16:24 +0000",
        "Message-Id": "<1579547786-7650-4-git-send-email-viacheslavo@mellanox.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1579547786-7650-1-git-send-email-viacheslavo@mellanox.com>",
        "References": "<20191118094938.192850-1-shahafs@mellanox.com>\n <1579547786-7650-1-git-send-email-viacheslavo@mellanox.com>",
        "Subject": "[dpdk-dev] [PATCH v6 3/5] mbuf: create packet pool with external\n\tmemory buffers",
        "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 <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",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "The dedicated routine rte_pktmbuf_pool_create_extbuf() is\nprovided to create mbuf pool with data buffers located in\nthe pinned external memory. The application provides the\nexternal memory description and routine initializes each\nmbuf with appropriate virtual and physical buffer address.\nIt is entirely application responsibility to register\nexternal memory with rte_extmem_register() API, map this\nmemory, etc.\n\nThe new introduced flag RTE_PKTMBUF_POOL_F_PINNED_EXT_BUF\nis set in private pool structure, specifying the new special\npool type. The allocated mbufs from pool of this kind will\nhave the EXT_ATTACHED_MBUF flag set and initialiazed shared\ninfo structure, allowing cloning with regular mbufs (without\nattached external buffers of any kind).\n\nSigned-off-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>\nAcked-by: Olivier Matz <olivier.matz@6wind.com>\n---\n lib/librte_mbuf/rte_mbuf.c           | 204 ++++++++++++++++++++++++++++++++++-\n lib/librte_mbuf/rte_mbuf.h           |  58 +++++++++-\n lib/librte_mbuf/rte_mbuf_version.map |   1 +\n 3 files changed, 260 insertions(+), 3 deletions(-)",
    "diff": "diff --git a/lib/librte_mbuf/rte_mbuf.c b/lib/librte_mbuf/rte_mbuf.c\nindex 8fa7f49..25eea1d 100644\n--- a/lib/librte_mbuf/rte_mbuf.c\n+++ b/lib/librte_mbuf/rte_mbuf.c\n@@ -59,9 +59,12 @@\n \t}\n \n \tRTE_ASSERT(mp->elt_size >= sizeof(struct rte_mbuf) +\n-\t\tuser_mbp_priv->mbuf_data_room_size +\n+\t\t((user_mbp_priv->flags & RTE_PKTMBUF_POOL_F_PINNED_EXT_BUF) ?\n+\t\t\tsizeof(struct rte_mbuf_ext_shared_info) :\n+\t\t\tuser_mbp_priv->mbuf_data_room_size) +\n \t\tuser_mbp_priv->mbuf_priv_size);\n-\tRTE_ASSERT(user_mbp_priv->flags == 0);\n+\tRTE_ASSERT((user_mbp_priv->flags &\n+\t\t    ~RTE_PKTMBUF_POOL_F_PINNED_EXT_BUF) == 0);\n \n \tmbp_priv = rte_mempool_get_priv(mp);\n \tmemcpy(mbp_priv, user_mbp_priv, sizeof(*mbp_priv));\n@@ -107,6 +110,116 @@\n \tm->next = NULL;\n }\n \n+/*\n+ * @internal The callback routine called when reference counter in shinfo\n+ * for mbufs with pinned external buffer reaches zero. It means there is\n+ * no more reference to buffer backing mbuf and this one should be freed.\n+ * This routine is called for the regular (not with pinned external or\n+ * indirect buffer) mbufs on detaching from the mbuf with pinned external\n+ * buffer.\n+ */\n+static void rte_pktmbuf_free_pinned_extmem(void *addr, void *opaque)\n+{\n+\tstruct rte_mbuf *m = opaque;\n+\n+\tRTE_SET_USED(addr);\n+\tRTE_ASSERT(RTE_MBUF_HAS_EXTBUF(m));\n+\tRTE_ASSERT(RTE_MBUF_HAS_PINNED_EXTBUF(m));\n+\tRTE_ASSERT(m->shinfo->fcb_opaque == m);\n+\n+\trte_mbuf_ext_refcnt_set(m->shinfo, 1);\n+\tm->ol_flags = EXT_ATTACHED_MBUF;\n+\tif (m->next != NULL) {\n+\t\tm->next = NULL;\n+\t\tm->nb_segs = 1;\n+\t}\n+\trte_mbuf_raw_free(m);\n+}\n+\n+/** The context to initialize the mbufs with pinned external buffers. */\n+struct rte_pktmbuf_extmem_init_ctx {\n+\tconst struct rte_pktmbuf_extmem *ext_mem; /* descriptor array. */\n+\tunsigned int ext_num; /* number of descriptors in array. */\n+\tunsigned int ext; /* loop descriptor index. */\n+\tsize_t off; /* loop buffer offset. */\n+};\n+\n+/**\n+ * @internal Packet mbuf constructor for pools with pinned external memory.\n+ *\n+ * This function initializes some fields in the mbuf structure that are\n+ * not modified by the user once created (origin pool, buffer start\n+ * address, and so on). This function is given as a callback function to\n+ * rte_mempool_obj_iter() called from rte_mempool_create_extmem().\n+ *\n+ * @param mp\n+ *   The mempool from which mbufs originate.\n+ * @param opaque_arg\n+ *   A pointer to the rte_pktmbuf_extmem_init_ctx - initialization\n+ *   context structure\n+ * @param m\n+ *   The mbuf to initialize.\n+ * @param i\n+ *   The index of the mbuf in the pool table.\n+ */\n+static void\n+__rte_pktmbuf_init_extmem(struct rte_mempool *mp,\n+\t\t\t  void *opaque_arg,\n+\t\t\t  void *_m,\n+\t\t\t  __attribute__((unused)) unsigned int i)\n+{\n+\tstruct rte_mbuf *m = _m;\n+\tstruct rte_pktmbuf_extmem_init_ctx *ctx = opaque_arg;\n+\tconst struct rte_pktmbuf_extmem *ext_mem;\n+\tuint32_t mbuf_size, buf_len, priv_size;\n+\tstruct rte_mbuf_ext_shared_info *shinfo;\n+\n+\tpriv_size = rte_pktmbuf_priv_size(mp);\n+\tmbuf_size = sizeof(struct rte_mbuf) + priv_size;\n+\tbuf_len = rte_pktmbuf_data_room_size(mp);\n+\n+\tRTE_ASSERT(RTE_ALIGN(priv_size, RTE_MBUF_PRIV_ALIGN) == priv_size);\n+\tRTE_ASSERT(mp->elt_size >= mbuf_size);\n+\tRTE_ASSERT(buf_len <= UINT16_MAX);\n+\n+\tmemset(m, 0, mbuf_size);\n+\tm->priv_size = priv_size;\n+\tm->buf_len = (uint16_t)buf_len;\n+\n+\t/* set the data buffer pointers to external memory */\n+\text_mem = ctx->ext_mem + ctx->ext;\n+\n+\tRTE_ASSERT(ctx->ext < ctx->ext_num);\n+\tRTE_ASSERT(ctx->off < ext_mem->buf_len);\n+\n+\tm->buf_addr = RTE_PTR_ADD(ext_mem->buf_ptr, ctx->off);\n+\tm->buf_iova = ext_mem->buf_iova == RTE_BAD_IOVA ?\n+\t\t      RTE_BAD_IOVA : (ext_mem->buf_iova + ctx->off);\n+\n+\tctx->off += ext_mem->elt_size;\n+\tif (ctx->off >= ext_mem->buf_len) {\n+\t\tctx->off = 0;\n+\t\t++ctx->ext;\n+\t}\n+\t/* keep some headroom between start of buffer and data */\n+\tm->data_off = RTE_MIN(RTE_PKTMBUF_HEADROOM, (uint16_t)m->buf_len);\n+\n+\t/* init some constant fields */\n+\tm->pool = mp;\n+\tm->nb_segs = 1;\n+\tm->port = MBUF_INVALID_PORT;\n+\tm->ol_flags = EXT_ATTACHED_MBUF;\n+\trte_mbuf_refcnt_set(m, 1);\n+\tm->next = NULL;\n+\n+\t/* init external buffer shared info items */\n+\tshinfo = RTE_PTR_ADD(m, mbuf_size);\n+\tm->shinfo = shinfo;\n+\tshinfo->free_cb = rte_pktmbuf_free_pinned_extmem;\n+\tshinfo->fcb_opaque = m;\n+\trte_mbuf_ext_refcnt_set(shinfo, 1);\n+}\n+\n /* Helper to create a mbuf pool with given mempool ops name*/\n struct rte_mempool *\n rte_pktmbuf_pool_create_by_ops(const char *name, unsigned int n,\n@@ -169,6 +282,93 @@ struct rte_mempool *\n \t\t\tdata_room_size, socket_id, NULL);\n }\n \n+/* Helper to create a mbuf pool with pinned external data buffers. */\n+struct rte_mempool *\n+rte_pktmbuf_pool_create_extbuf(const char *name, unsigned int n,\n+\tunsigned int cache_size, uint16_t priv_size,\n+\tuint16_t data_room_size, int socket_id,\n+\tconst struct rte_pktmbuf_extmem *ext_mem,\n+\tunsigned int ext_num)\n+{\n+\tstruct rte_mempool *mp;\n+\tstruct rte_pktmbuf_pool_private mbp_priv;\n+\tstruct rte_pktmbuf_extmem_init_ctx init_ctx;\n+\tconst char *mp_ops_name;\n+\tunsigned int elt_size;\n+\tunsigned int i, n_elts = 0;\n+\tint ret;\n+\n+\tif (RTE_ALIGN(priv_size, RTE_MBUF_PRIV_ALIGN) != priv_size) {\n+\t\tRTE_LOG(ERR, MBUF, \"mbuf priv_size=%u is not aligned\\n\",\n+\t\t\tpriv_size);\n+\t\trte_errno = EINVAL;\n+\t\treturn NULL;\n+\t}\n+\t/* Check the external memory descriptors. */\n+\tfor (i = 0; i < ext_num; i++) {\n+\t\tconst struct rte_pktmbuf_extmem *extm = ext_mem + i;\n+\n+\t\tif (!extm->elt_size || !extm->buf_len || !extm->buf_ptr) {\n+\t\t\tRTE_LOG(ERR, MBUF, \"invalid extmem descriptor\\n\");\n+\t\t\trte_errno = EINVAL;\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tif (data_room_size > extm->elt_size) {\n+\t\t\tRTE_LOG(ERR, MBUF, \"ext elt_size=%u is too small\\n\",\n+\t\t\t\tpriv_size);\n+\t\t\trte_errno = EINVAL;\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tn_elts += extm->buf_len / extm->elt_size;\n+\t}\n+\t/* Check whether enough external memory provided. */\n+\tif (n_elts < n) {\n+\t\tRTE_LOG(ERR, MBUF, \"not enough extmem\\n\");\n+\t\trte_errno = ENOMEM;\n+\t\treturn NULL;\n+\t}\n+\telt_size = sizeof(struct rte_mbuf) +\n+\t\t   (unsigned int)priv_size +\n+\t\t   sizeof(struct rte_mbuf_ext_shared_info);\n+\n+\tmemset(&mbp_priv, 0, sizeof(mbp_priv));\n+\tmbp_priv.mbuf_data_room_size = data_room_size;\n+\tmbp_priv.mbuf_priv_size = priv_size;\n+\tmbp_priv.flags = RTE_PKTMBUF_POOL_F_PINNED_EXT_BUF;\n+\n+\tmp = rte_mempool_create_empty(name, n, elt_size, cache_size,\n+\t\t sizeof(struct rte_pktmbuf_pool_private), socket_id, 0);\n+\tif (mp == NULL)\n+\t\treturn NULL;\n+\n+\tmp_ops_name = rte_mbuf_best_mempool_ops();\n+\tret = rte_mempool_set_ops_byname(mp, mp_ops_name, NULL);\n+\tif (ret != 0) {\n+\t\tRTE_LOG(ERR, MBUF, \"error setting mempool handler\\n\");\n+\t\trte_mempool_free(mp);\n+\t\trte_errno = -ret;\n+\t\treturn NULL;\n+\t}\n+\trte_pktmbuf_pool_init(mp, &mbp_priv);\n+\n+\tret = rte_mempool_populate_default(mp);\n+\tif (ret < 0) {\n+\t\trte_mempool_free(mp);\n+\t\trte_errno = -ret;\n+\t\treturn NULL;\n+\t}\n+\n+\tinit_ctx = (struct rte_pktmbuf_extmem_init_ctx){\n+\t\t.ext_mem = ext_mem,\n+\t\t.ext_num = ext_num,\n+\t\t.ext = 0,\n+\t\t.off = 0,\n+\t};\n+\trte_mempool_obj_iter(mp, __rte_pktmbuf_init_extmem, &init_ctx);\n+\n+\treturn mp;\n+}\n+\n /* do some sanity checks on a mbuf: panic if it fails */\n void\n rte_mbuf_sanity_check(const struct rte_mbuf *m, int is_header)\ndiff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h\nindex c4f5085..5902389 100644\n--- a/lib/librte_mbuf/rte_mbuf.h\n+++ b/lib/librte_mbuf/rte_mbuf.h\n@@ -637,7 +637,6 @@ static inline struct rte_mbuf *rte_mbuf_raw_alloc(struct rte_mempool *mp)\n void rte_pktmbuf_init(struct rte_mempool *mp, void *opaque_arg,\n \t\t      void *m, unsigned i);\n \n-\n /**\n  * A  packet mbuf pool constructor.\n  *\n@@ -738,6 +737,63 @@ struct rte_mempool *\n \tunsigned int cache_size, uint16_t priv_size, uint16_t data_room_size,\n \tint socket_id, const char *ops_name);\n \n+/** A structure that describes the pinned external buffer segment. */\n+struct rte_pktmbuf_extmem {\n+\tvoid *buf_ptr;\t\t/**< The virtual address of data buffer. */\n+\trte_iova_t buf_iova;\t/**< The IO address of the data buffer. */\n+\tsize_t buf_len;\t\t/**< External buffer length in bytes. */\n+\tuint16_t elt_size;\t/**< mbuf element size in bytes. */\n+};\n+\n+/**\n+ * Create a mbuf pool with external pinned data buffers.\n+ *\n+ * This function creates and initializes a packet mbuf pool that contains\n+ * only mbufs with external buffer. It is a wrapper to rte_mempool functions.\n+ *\n+ * @param name\n+ *   The name of the mbuf pool.\n+ * @param n\n+ *   The number of elements in the mbuf pool. The optimum size (in terms\n+ *   of memory usage) for a mempool is when n is a power of two minus one:\n+ *   n = (2^q - 1).\n+ * @param cache_size\n+ *   Size of the per-core object cache. See rte_mempool_create() for\n+ *   details.\n+ * @param priv_size\n+ *   Size of application private are between the rte_mbuf structure\n+ *   and the data buffer. This value must be aligned to RTE_MBUF_PRIV_ALIGN.\n+ * @param data_room_size\n+ *   Size of data buffer in each mbuf, including RTE_PKTMBUF_HEADROOM.\n+ * @param socket_id\n+ *   The socket identifier where the memory should be allocated. The\n+ *   value can be *SOCKET_ID_ANY* if there is no NUMA constraint for the\n+ *   reserved zone.\n+ * @param ext_mem\n+ *   Pointer to the array of structures describing the external memory\n+ *   for data buffers. It is caller responsibility to register this memory\n+ *   with rte_extmem_register() (if needed), map this memory to appropriate\n+ *   physical device, etc.\n+ * @param ext_num\n+ *   Number of elements in the ext_mem array.\n+ * @return\n+ *   The pointer to the new allocated mempool, on success. NULL on error\n+ *   with rte_errno set appropriately. Possible rte_errno values include:\n+ *    - E_RTE_NO_CONFIG - function could not get pointer to rte_config structure\n+ *    - E_RTE_SECONDARY - function was called from a secondary process instance\n+ *    - EINVAL - cache size provided is too large, or priv_size is not aligned.\n+ *    - ENOSPC - the maximum number of memzones has already been allocated\n+ *    - EEXIST - a memzone with the same name already exists\n+ *    - ENOMEM - no appropriate memory area found in which to create memzone\n+ */\n+__rte_experimental\n+struct rte_mempool *\n+rte_pktmbuf_pool_create_extbuf(const char *name, unsigned int n,\n+\tunsigned int cache_size, uint16_t priv_size,\n+\tuint16_t data_room_size, int socket_id,\n+\tconst struct rte_pktmbuf_extmem *ext_mem,\n+\tunsigned int ext_num);\n+\n /**\n  * Get the data room size of mbufs stored in a pktmbuf_pool\n  *\ndiff --git a/lib/librte_mbuf/rte_mbuf_version.map b/lib/librte_mbuf/rte_mbuf_version.map\nindex 3bbb476..ab161bc 100644\n--- a/lib/librte_mbuf/rte_mbuf_version.map\n+++ b/lib/librte_mbuf/rte_mbuf_version.map\n@@ -44,5 +44,6 @@ EXPERIMENTAL {\n \trte_mbuf_dyn_dump;\n \trte_pktmbuf_copy;\n \trte_pktmbuf_free_bulk;\n+\trte_pktmbuf_pool_create_extbuf;\n \n };\n",
    "prefixes": [
        "v6",
        "3/5"
    ]
}