get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 7775,
    "url": "https://patches.dpdk.org/api/patches/7775/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1445351774-4459-2-git-send-email-piotrx.t.azarewicz@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": "<1445351774-4459-2-git-send-email-piotrx.t.azarewicz@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1445351774-4459-2-git-send-email-piotrx.t.azarewicz@intel.com",
    "date": "2015-10-20T14:36:12",
    "name": "[dpdk-dev,v3,1/3] port: add mp/mc ring ports",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "52ed9784f16ace1cd711a88f19c646c75eb4fe43",
    "submitter": {
        "id": 273,
        "url": "https://patches.dpdk.org/api/people/273/?format=api",
        "name": "Piotr Azarewicz",
        "email": "piotrx.t.azarewicz@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1445351774-4459-2-git-send-email-piotrx.t.azarewicz@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/7775/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/7775/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 7FE988E83;\n\tTue, 20 Oct 2015 16:38:30 +0200 (CEST)",
            "from mga09.intel.com (mga09.intel.com [134.134.136.24])\n\tby dpdk.org (Postfix) with ESMTP id C01F88DB1\n\tfor <dev@dpdk.org>; Tue, 20 Oct 2015 16:38:28 +0200 (CEST)",
            "from orsmga001.jf.intel.com ([10.7.209.18])\n\tby orsmga102.jf.intel.com with ESMTP; 20 Oct 2015 07:37:39 -0700",
            "from unknown (HELO stargo) ([10.217.248.233])\n\tby orsmga001.jf.intel.com with SMTP; 20 Oct 2015 07:37:36 -0700",
            "by stargo (sSMTP sendmail emulation);\n\tTue, 20 Oct 2015 16:38:33 +0200"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.17,707,1437462000\"; d=\"scan'208\";a=\"798110730\"",
        "From": "Piotr Azarewicz <piotrx.t.azarewicz@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Tue, 20 Oct 2015 16:36:12 +0200",
        "Message-Id": "<1445351774-4459-2-git-send-email-piotrx.t.azarewicz@intel.com>",
        "X-Mailer": "git-send-email 1.9.1",
        "In-Reply-To": "<1445351774-4459-1-git-send-email-piotrx.t.azarewicz@intel.com>",
        "References": "<1443088539-28194-1-git-send-email-piotrx.t.azarewicz@intel.com>\n\t<1445351774-4459-1-git-send-email-piotrx.t.azarewicz@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v3 1/3] port: add mp/mc ring ports",
        "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": "ring_multi_reader input port (on top of multi consumer rte_ring)\nring_multi_writer output port (on top of multi producer rte_ring)\n\nSigned-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>\n---\n lib/librte_port/rte_port_ring.c      |  311 +++++++++++++++++++++++++++++++---\n lib/librte_port/rte_port_ring.h      |   35 +++-\n lib/librte_port/rte_port_version.map |    9 +\n 3 files changed, 325 insertions(+), 30 deletions(-)",
    "diff": "diff --git a/lib/librte_port/rte_port_ring.c b/lib/librte_port/rte_port_ring.c\nindex 9461c05..755dfc1 100644\n--- a/lib/librte_port/rte_port_ring.c\n+++ b/lib/librte_port/rte_port_ring.c\n@@ -63,15 +63,19 @@ struct rte_port_ring_reader {\n };\n \n static void *\n-rte_port_ring_reader_create(void *params, int socket_id)\n+rte_port_ring_reader_create_internal(void *params, int socket_id,\n+\tuint32_t is_multi)\n {\n \tstruct rte_port_ring_reader_params *conf =\n \t\t\t(struct rte_port_ring_reader_params *) params;\n \tstruct rte_port_ring_reader *port;\n \n \t/* Check input parameters */\n-\tif (conf == NULL) {\n-\t\tRTE_LOG(ERR, PORT, \"%s: params is NULL\\n\", __func__);\n+\tif ((conf == NULL) ||\n+\t\t(conf->ring == NULL) ||\n+\t\t(conf->ring->cons.sc_dequeue && is_multi) ||\n+\t\t(!(conf->ring->cons.sc_dequeue) && !is_multi)) {\n+\t\tRTE_LOG(ERR, PORT, \"%s: Invalid Parameters\\n\", __func__);\n \t\treturn NULL;\n \t}\n \n@@ -89,6 +93,18 @@ rte_port_ring_reader_create(void *params, int socket_id)\n \treturn port;\n }\n \n+static void *\n+rte_port_ring_reader_create(void *params, int socket_id)\n+{\n+\treturn rte_port_ring_reader_create_internal(params, socket_id, 0);\n+}\n+\n+static void *\n+rte_port_ring_multi_reader_create(void *params, int socket_id)\n+{\n+\treturn rte_port_ring_reader_create_internal(params, socket_id, 1);\n+}\n+\n static int\n rte_port_ring_reader_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)\n {\n@@ -102,6 +118,19 @@ rte_port_ring_reader_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)\n }\n \n static int\n+rte_port_ring_multi_reader_rx(void *port, struct rte_mbuf **pkts,\n+\tuint32_t n_pkts)\n+{\n+\tstruct rte_port_ring_reader *p = (struct rte_port_ring_reader *) port;\n+\tuint32_t nb_rx;\n+\n+\tnb_rx = rte_ring_mc_dequeue_burst(p->ring, (void **) pkts, n_pkts);\n+\tRTE_PORT_RING_READER_STATS_PKTS_IN_ADD(p, nb_rx);\n+\n+\treturn nb_rx;\n+}\n+\n+static int\n rte_port_ring_reader_free(void *port)\n {\n \tif (port == NULL) {\n@@ -155,10 +184,12 @@ struct rte_port_ring_writer {\n \tuint32_t tx_burst_sz;\n \tuint32_t tx_buf_count;\n \tuint64_t bsz_mask;\n+\tuint32_t is_multi;\n };\n \n static void *\n-rte_port_ring_writer_create(void *params, int socket_id)\n+rte_port_ring_writer_create_internal(void *params, int socket_id,\n+\tuint32_t is_multi)\n {\n \tstruct rte_port_ring_writer_params *conf =\n \t\t\t(struct rte_port_ring_writer_params *) params;\n@@ -166,7 +197,9 @@ rte_port_ring_writer_create(void *params, int socket_id)\n \n \t/* Check input parameters */\n \tif ((conf == NULL) ||\n-\t    (conf->ring == NULL) ||\n+\t\t(conf->ring == NULL) ||\n+\t\t(conf->ring->prod.sp_enqueue && is_multi) ||\n+\t\t(!(conf->ring->prod.sp_enqueue) && !is_multi) ||\n \t\t(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX)) {\n \t\tRTE_LOG(ERR, PORT, \"%s: Invalid Parameters\\n\", __func__);\n \t\treturn NULL;\n@@ -185,10 +218,23 @@ rte_port_ring_writer_create(void *params, int socket_id)\n \tport->tx_burst_sz = conf->tx_burst_sz;\n \tport->tx_buf_count = 0;\n \tport->bsz_mask = 1LLU << (conf->tx_burst_sz - 1);\n+\tport->is_multi = is_multi;\n \n \treturn port;\n }\n \n+static void *\n+rte_port_ring_writer_create(void *params, int socket_id)\n+{\n+\treturn rte_port_ring_writer_create_internal(params, socket_id, 0);\n+}\n+\n+static void *\n+rte_port_ring_multi_writer_create(void *params, int socket_id)\n+{\n+\treturn rte_port_ring_writer_create_internal(params, socket_id, 1);\n+}\n+\n static inline void\n send_burst(struct rte_port_ring_writer *p)\n {\n@@ -204,6 +250,21 @@ send_burst(struct rte_port_ring_writer *p)\n \tp->tx_buf_count = 0;\n }\n \n+static inline void\n+send_burst_mp(struct rte_port_ring_writer *p)\n+{\n+\tuint32_t nb_tx;\n+\n+\tnb_tx = rte_ring_mp_enqueue_burst(p->ring, (void **)p->tx_buf,\n+\t\t\tp->tx_buf_count);\n+\n+\tRTE_PORT_RING_WRITER_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - nb_tx);\n+\tfor ( ; nb_tx < p->tx_buf_count; nb_tx++)\n+\t\trte_pktmbuf_free(p->tx_buf[nb_tx]);\n+\n+\tp->tx_buf_count = 0;\n+}\n+\n static int\n rte_port_ring_writer_tx(void *port, struct rte_mbuf *pkt)\n {\n@@ -218,9 +279,23 @@ rte_port_ring_writer_tx(void *port, struct rte_mbuf *pkt)\n }\n \n static int\n-rte_port_ring_writer_tx_bulk(void *port,\n+rte_port_ring_multi_writer_tx(void *port, struct rte_mbuf *pkt)\n+{\n+\tstruct rte_port_ring_writer *p = (struct rte_port_ring_writer *) port;\n+\n+\tp->tx_buf[p->tx_buf_count++] = pkt;\n+\tRTE_PORT_RING_WRITER_STATS_PKTS_IN_ADD(p, 1);\n+\tif (p->tx_buf_count >= p->tx_burst_sz)\n+\t\tsend_burst_mp(p);\n+\n+\treturn 0;\n+}\n+\n+static inline int __attribute__((always_inline))\n+rte_port_ring_writer_tx_bulk_internal(void *port,\n \t\tstruct rte_mbuf **pkts,\n-\t\tuint64_t pkts_mask)\n+\t\tuint64_t pkts_mask,\n+\t\tuint32_t is_multi)\n {\n \tstruct rte_port_ring_writer *p =\n \t\t(struct rte_port_ring_writer *) port;\n@@ -234,11 +309,20 @@ rte_port_ring_writer_tx_bulk(void *port,\n \t\tuint64_t n_pkts = __builtin_popcountll(pkts_mask);\n \t\tuint32_t n_pkts_ok;\n \n-\t\tif (tx_buf_count)\n-\t\t\tsend_burst(p);\n+\t\tif (tx_buf_count) {\n+\t\t\tif (is_multi)\n+\t\t\t\tsend_burst_mp(p);\n+\t\t\telse\n+\t\t\t\tsend_burst(p);\n+\t\t}\n \n \t\tRTE_PORT_RING_WRITER_STATS_PKTS_IN_ADD(p, n_pkts);\n-\t\tn_pkts_ok = rte_ring_sp_enqueue_burst(p->ring, (void **)pkts, n_pkts);\n+\t\tif (is_multi)\n+\t\t\tn_pkts_ok = rte_ring_mp_enqueue_burst(p->ring, (void **)pkts,\n+\t\t\t\tn_pkts);\n+\t\telse\n+\t\t\tn_pkts_ok = rte_ring_sp_enqueue_burst(p->ring, (void **)pkts,\n+\t\t\t\tn_pkts);\n \n \t\tRTE_PORT_RING_WRITER_STATS_PKTS_DROP_ADD(p, n_pkts - n_pkts_ok);\n \t\tfor ( ; n_pkts_ok < n_pkts; n_pkts_ok++) {\n@@ -258,14 +342,34 @@ rte_port_ring_writer_tx_bulk(void *port,\n \t\t}\n \n \t\tp->tx_buf_count = tx_buf_count;\n-\t\tif (tx_buf_count >= p->tx_burst_sz)\n-\t\t\tsend_burst(p);\n+\t\tif (tx_buf_count >= p->tx_burst_sz) {\n+\t\t\tif (is_multi)\n+\t\t\t\tsend_burst_mp(p);\n+\t\t\telse\n+\t\t\t\tsend_burst(p);\n+\t\t}\n \t}\n \n \treturn 0;\n }\n \n static int\n+rte_port_ring_writer_tx_bulk(void *port,\n+\t\tstruct rte_mbuf **pkts,\n+\t\tuint64_t pkts_mask)\n+{\n+\treturn rte_port_ring_writer_tx_bulk_internal(port, pkts, pkts_mask, 0);\n+}\n+\n+static int\n+rte_port_ring_multi_writer_tx_bulk(void *port,\n+\t\tstruct rte_mbuf **pkts,\n+\t\tuint64_t pkts_mask)\n+{\n+\treturn rte_port_ring_writer_tx_bulk_internal(port, pkts, pkts_mask, 1);\n+}\n+\n+static int\n rte_port_ring_writer_flush(void *port)\n {\n \tstruct rte_port_ring_writer *p = (struct rte_port_ring_writer *) port;\n@@ -277,14 +381,31 @@ rte_port_ring_writer_flush(void *port)\n }\n \n static int\n+rte_port_ring_multi_writer_flush(void *port)\n+{\n+\tstruct rte_port_ring_writer *p = (struct rte_port_ring_writer *) port;\n+\n+\tif (p->tx_buf_count > 0)\n+\t\tsend_burst_mp(p);\n+\n+\treturn 0;\n+}\n+\n+static int\n rte_port_ring_writer_free(void *port)\n {\n+\tstruct rte_port_ring_writer *p = (struct rte_port_ring_writer *) port;\n+\n \tif (port == NULL) {\n \t\tRTE_LOG(ERR, PORT, \"%s: Port is NULL\\n\", __func__);\n \t\treturn -EINVAL;\n \t}\n \n-\trte_port_ring_writer_flush(port);\n+\tif (p->is_multi)\n+\t\trte_port_ring_multi_writer_flush(port);\n+\telse\n+\t\trte_port_ring_writer_flush(port);\n+\n \trte_free(port);\n \n \treturn 0;\n@@ -332,10 +453,12 @@ struct rte_port_ring_writer_nodrop {\n \tuint32_t tx_buf_count;\n \tuint64_t bsz_mask;\n \tuint64_t n_retries;\n+\tuint32_t is_multi;\n };\n \n static void *\n-rte_port_ring_writer_nodrop_create(void *params, int socket_id)\n+rte_port_ring_writer_nodrop_create_internal(void *params, int socket_id,\n+\tuint32_t is_multi)\n {\n \tstruct rte_port_ring_writer_nodrop_params *conf =\n \t\t\t(struct rte_port_ring_writer_nodrop_params *) params;\n@@ -343,7 +466,9 @@ rte_port_ring_writer_nodrop_create(void *params, int socket_id)\n \n \t/* Check input parameters */\n \tif ((conf == NULL) ||\n-\t    (conf->ring == NULL) ||\n+\t\t(conf->ring == NULL) ||\n+\t\t(conf->ring->prod.sp_enqueue && is_multi) ||\n+\t\t(!(conf->ring->prod.sp_enqueue) && !is_multi) ||\n \t\t(conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX)) {\n \t\tRTE_LOG(ERR, PORT, \"%s: Invalid Parameters\\n\", __func__);\n \t\treturn NULL;\n@@ -362,6 +487,7 @@ rte_port_ring_writer_nodrop_create(void *params, int socket_id)\n \tport->tx_burst_sz = conf->tx_burst_sz;\n \tport->tx_buf_count = 0;\n \tport->bsz_mask = 1LLU << (conf->tx_burst_sz - 1);\n+\tport->is_multi = is_multi;\n \n \t/*\n \t * When n_retries is 0 it means that we should wait for every packet to\n@@ -373,6 +499,18 @@ rte_port_ring_writer_nodrop_create(void *params, int socket_id)\n \treturn port;\n }\n \n+static void *\n+rte_port_ring_writer_nodrop_create(void *params, int socket_id)\n+{\n+\treturn rte_port_ring_writer_nodrop_create_internal(params, socket_id, 0);\n+}\n+\n+static void *\n+rte_port_ring_multi_writer_nodrop_create(void *params, int socket_id)\n+{\n+\treturn rte_port_ring_writer_nodrop_create_internal(params, socket_id, 1);\n+}\n+\n static inline void\n send_burst_nodrop(struct rte_port_ring_writer_nodrop *p)\n {\n@@ -402,6 +540,35 @@ send_burst_nodrop(struct rte_port_ring_writer_nodrop *p)\n \tp->tx_buf_count = 0;\n }\n \n+static inline void\n+send_burst_mp_nodrop(struct rte_port_ring_writer_nodrop *p)\n+{\n+\tuint32_t nb_tx = 0, i;\n+\n+\tnb_tx = rte_ring_mp_enqueue_burst(p->ring, (void **)p->tx_buf,\n+\t\t\t\tp->tx_buf_count);\n+\n+\t/* We sent all the packets in a first try */\n+\tif (nb_tx >= p->tx_buf_count)\n+\t\treturn;\n+\n+\tfor (i = 0; i < p->n_retries; i++) {\n+\t\tnb_tx += rte_ring_mp_enqueue_burst(p->ring,\n+\t\t\t\t(void **) (p->tx_buf + nb_tx), p->tx_buf_count - nb_tx);\n+\n+\t\t/* We sent all the packets in more than one try */\n+\t\tif (nb_tx >= p->tx_buf_count)\n+\t\t\treturn;\n+\t}\n+\n+\t/* We didn't send the packets in maximum allowed attempts */\n+\tRTE_PORT_RING_WRITER_NODROP_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - nb_tx);\n+\tfor ( ; nb_tx < p->tx_buf_count; nb_tx++)\n+\t\trte_pktmbuf_free(p->tx_buf[nb_tx]);\n+\n+\tp->tx_buf_count = 0;\n+}\n+\n static int\n rte_port_ring_writer_nodrop_tx(void *port, struct rte_mbuf *pkt)\n {\n@@ -417,9 +584,24 @@ rte_port_ring_writer_nodrop_tx(void *port, struct rte_mbuf *pkt)\n }\n \n static int\n-rte_port_ring_writer_nodrop_tx_bulk(void *port,\n+rte_port_ring_multi_writer_nodrop_tx(void *port, struct rte_mbuf *pkt)\n+{\n+\tstruct rte_port_ring_writer_nodrop *p =\n+\t\t\t(struct rte_port_ring_writer_nodrop *) port;\n+\n+\tp->tx_buf[p->tx_buf_count++] = pkt;\n+\tRTE_PORT_RING_WRITER_NODROP_STATS_PKTS_IN_ADD(p, 1);\n+\tif (p->tx_buf_count >= p->tx_burst_sz)\n+\t\tsend_burst_mp_nodrop(p);\n+\n+\treturn 0;\n+}\n+\n+static inline int __attribute__((always_inline))\n+rte_port_ring_writer_nodrop_tx_bulk_internal(void *port,\n \t\tstruct rte_mbuf **pkts,\n-\t\tuint64_t pkts_mask)\n+\t\tuint64_t pkts_mask,\n+\t\tuint32_t is_multi)\n {\n \tstruct rte_port_ring_writer_nodrop *p =\n \t\t(struct rte_port_ring_writer_nodrop *) port;\n@@ -433,24 +615,37 @@ rte_port_ring_writer_nodrop_tx_bulk(void *port,\n \t\tuint64_t n_pkts = __builtin_popcountll(pkts_mask);\n \t\tuint32_t n_pkts_ok;\n \n-\t\tif (tx_buf_count)\n-\t\t\tsend_burst_nodrop(p);\n+\t\tif (tx_buf_count) {\n+\t\t\tif (is_multi)\n+\t\t\t\tsend_burst_mp_nodrop(p);\n+\t\t\telse\n+\t\t\t\tsend_burst_nodrop(p);\n+\t\t}\n \n \t\tRTE_PORT_RING_WRITER_NODROP_STATS_PKTS_IN_ADD(p, n_pkts);\n-\t\tn_pkts_ok = rte_ring_sp_enqueue_burst(p->ring, (void **)pkts, n_pkts);\n+\t\tif (is_multi)\n+\t\t\tn_pkts_ok =\n+\t\t\t\trte_ring_mp_enqueue_burst(p->ring, (void **)pkts, n_pkts);\n+\t\telse\n+\t\t\tn_pkts_ok =\n+\t\t\t\trte_ring_sp_enqueue_burst(p->ring, (void **)pkts, n_pkts);\n \n \t\tif (n_pkts_ok >= n_pkts)\n \t\t\treturn 0;\n \n \t\t/*\n-\t\t * If we didnt manage to send all packets in single burst, move\n+\t\t * If we didn't manage to send all packets in single burst, move\n \t\t * remaining packets to the buffer and call send burst.\n \t\t */\n \t\tfor (; n_pkts_ok < n_pkts; n_pkts_ok++) {\n \t\t\tstruct rte_mbuf *pkt = pkts[n_pkts_ok];\n+\n \t\t\tp->tx_buf[p->tx_buf_count++] = pkt;\n \t\t}\n-\t\tsend_burst_nodrop(p);\n+\t\tif (is_multi)\n+\t\t\tsend_burst_mp_nodrop(p);\n+\t\telse\n+\t\t\tsend_burst_nodrop(p);\n \t} else {\n \t\tfor ( ; pkts_mask; ) {\n \t\t\tuint32_t pkt_index = __builtin_ctzll(pkts_mask);\n@@ -463,14 +658,36 @@ rte_port_ring_writer_nodrop_tx_bulk(void *port,\n \t\t}\n \n \t\tp->tx_buf_count = tx_buf_count;\n-\t\tif (tx_buf_count >= p->tx_burst_sz)\n-\t\t\tsend_burst_nodrop(p);\n+\t\tif (tx_buf_count >= p->tx_burst_sz) {\n+\t\t\tif (is_multi)\n+\t\t\t\tsend_burst_mp_nodrop(p);\n+\t\t\telse\n+\t\t\t\tsend_burst_nodrop(p);\n+\t\t}\n \t}\n \n \treturn 0;\n }\n \n static int\n+rte_port_ring_writer_nodrop_tx_bulk(void *port,\n+\t\tstruct rte_mbuf **pkts,\n+\t\tuint64_t pkts_mask)\n+{\n+\treturn\n+\t\trte_port_ring_writer_nodrop_tx_bulk_internal(port, pkts, pkts_mask, 0);\n+}\n+\n+static int\n+rte_port_ring_multi_writer_nodrop_tx_bulk(void *port,\n+\t\tstruct rte_mbuf **pkts,\n+\t\tuint64_t pkts_mask)\n+{\n+\treturn\n+\t\trte_port_ring_writer_nodrop_tx_bulk_internal(port, pkts, pkts_mask, 1);\n+}\n+\n+static int\n rte_port_ring_writer_nodrop_flush(void *port)\n {\n \tstruct rte_port_ring_writer_nodrop *p =\n@@ -483,14 +700,33 @@ rte_port_ring_writer_nodrop_flush(void *port)\n }\n \n static int\n+rte_port_ring_multi_writer_nodrop_flush(void *port)\n+{\n+\tstruct rte_port_ring_writer_nodrop *p =\n+\t\t\t(struct rte_port_ring_writer_nodrop *) port;\n+\n+\tif (p->tx_buf_count > 0)\n+\t\tsend_burst_mp_nodrop(p);\n+\n+\treturn 0;\n+}\n+\n+static int\n rte_port_ring_writer_nodrop_free(void *port)\n {\n+\tstruct rte_port_ring_writer_nodrop *p =\n+\t\t\t(struct rte_port_ring_writer_nodrop *) port;\n+\n \tif (port == NULL) {\n \t\tRTE_LOG(ERR, PORT, \"%s: Port is NULL\\n\", __func__);\n \t\treturn -EINVAL;\n \t}\n \n-\trte_port_ring_writer_nodrop_flush(port);\n+\tif (p->is_multi)\n+\t\trte_port_ring_multi_writer_nodrop_flush(port);\n+\telse\n+\t\trte_port_ring_writer_nodrop_flush(port);\n+\n \trte_free(port);\n \n \treturn 0;\n@@ -539,3 +775,28 @@ struct rte_port_out_ops rte_port_ring_writer_nodrop_ops = {\n \t.f_flush = rte_port_ring_writer_nodrop_flush,\n \t.f_stats = rte_port_ring_writer_nodrop_stats_read,\n };\n+\n+struct rte_port_in_ops rte_port_ring_multi_reader_ops = {\n+\t.f_create = rte_port_ring_multi_reader_create,\n+\t.f_free = rte_port_ring_reader_free,\n+\t.f_rx = rte_port_ring_multi_reader_rx,\n+\t.f_stats = rte_port_ring_reader_stats_read,\n+};\n+\n+struct rte_port_out_ops rte_port_ring_multi_writer_ops = {\n+\t.f_create = rte_port_ring_multi_writer_create,\n+\t.f_free = rte_port_ring_writer_free,\n+\t.f_tx = rte_port_ring_multi_writer_tx,\n+\t.f_tx_bulk = rte_port_ring_multi_writer_tx_bulk,\n+\t.f_flush = rte_port_ring_multi_writer_flush,\n+\t.f_stats = rte_port_ring_writer_stats_read,\n+};\n+\n+struct rte_port_out_ops rte_port_ring_multi_writer_nodrop_ops = {\n+\t.f_create = rte_port_ring_multi_writer_nodrop_create,\n+\t.f_free = rte_port_ring_writer_nodrop_free,\n+\t.f_tx = rte_port_ring_multi_writer_nodrop_tx,\n+\t.f_tx_bulk = rte_port_ring_multi_writer_nodrop_tx_bulk,\n+\t.f_flush = rte_port_ring_multi_writer_nodrop_flush,\n+\t.f_stats = rte_port_ring_writer_nodrop_stats_read,\n+};\ndiff --git a/lib/librte_port/rte_port_ring.h b/lib/librte_port/rte_port_ring.h\nindex 89a219b..de377d2 100644\n--- a/lib/librte_port/rte_port_ring.h\n+++ b/lib/librte_port/rte_port_ring.h\n@@ -42,8 +42,14 @@ extern \"C\" {\n  * @file\n  * RTE Port Ring\n  *\n- * ring_reader: input port built on top of pre-initialized single consumer ring\n- * ring_writer: output port built on top of pre-initialized single producer ring\n+ * ring_reader:\n+ *      input port built on top of pre-initialized single consumer ring\n+ * ring_writer:\n+ *      output port built on top of pre-initialized single producer ring\n+ * ring_multi_reader:\n+ *      input port built on top of pre-initialized multi consumers ring\n+ * ring_multi_writer:\n+ *      output port built on top of pre-initialized multi producers ring\n  *\n  ***/\n \n@@ -55,7 +61,7 @@ extern \"C\" {\n \n /** ring_reader port parameters */\n struct rte_port_ring_reader_params {\n-\t/** Underlying single consumer ring that has to be pre-initialized */\n+\t/** Underlying consumer ring that has to be pre-initialized */\n \tstruct rte_ring *ring;\n };\n \n@@ -64,7 +70,7 @@ extern struct rte_port_in_ops rte_port_ring_reader_ops;\n \n /** ring_writer port parameters */\n struct rte_port_ring_writer_params {\n-\t/** Underlying single producer ring that has to be pre-initialized */\n+\t/** Underlying producer ring that has to be pre-initialized */\n \tstruct rte_ring *ring;\n \n \t/** Recommended burst size to ring. The actual burst size can be\n@@ -77,7 +83,7 @@ extern struct rte_port_out_ops rte_port_ring_writer_ops;\n \n /** ring_writer_nodrop port parameters */\n struct rte_port_ring_writer_nodrop_params {\n-\t/** Underlying single producer ring that has to be pre-initialized */\n+\t/** Underlying producer ring that has to be pre-initialized */\n \tstruct rte_ring *ring;\n \n \t/** Recommended burst size to ring. The actual burst size can be\n@@ -91,6 +97,25 @@ struct rte_port_ring_writer_nodrop_params {\n /** ring_writer_nodrop port operations */\n extern struct rte_port_out_ops rte_port_ring_writer_nodrop_ops;\n \n+/** ring_multi_reader port parameters */\n+#define rte_port_ring_multi_reader_params rte_port_ring_reader_params\n+\n+/** ring_multi_reader port operations */\n+extern struct rte_port_in_ops rte_port_ring_multi_reader_ops;\n+\n+/** ring_multi_writer port parameters */\n+#define rte_port_ring_multi_writer_params rte_port_ring_writer_params\n+\n+/** ring_multi_writer port operations */\n+extern struct rte_port_out_ops rte_port_ring_multi_writer_ops;\n+\n+/** ring_multi_writer_nodrop port parameters */\n+#define rte_port_ring_multi_writer_nodrop_params \\\n+\trte_port_ring_writer_nodrop_params\n+\n+/** ring_multi_writer_nodrop port operations */\n+extern struct rte_port_out_ops rte_port_ring_multi_writer_nodrop_ops;\n+\n #ifdef __cplusplus\n }\n #endif\ndiff --git a/lib/librte_port/rte_port_version.map b/lib/librte_port/rte_port_version.map\nindex 4e49ff6..7a0b34d 100644\n--- a/lib/librte_port/rte_port_version.map\n+++ b/lib/librte_port/rte_port_version.map\n@@ -26,3 +26,12 @@ DPDK_2.1 {\n \trte_port_ring_writer_nodrop_ops;\n \n } DPDK_2.0;\n+\n+DPDK_2.2 {\n+\tglobal:\n+\n+\trte_port_ring_multi_reader_ops;\n+\trte_port_ring_multi_writer_ops;\n+\trte_port_ring_multi_writer_nodrop_ops;\n+\n+} DPDK_2.1;\n",
    "prefixes": [
        "dpdk-dev",
        "v3",
        "1/3"
    ]
}