get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 11386,
    "url": "http://patches.dpdk.org/api/patches/11386/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1457607478-2184-3-git-send-email-tomaszx.kulasek@intel.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": "<1457607478-2184-3-git-send-email-tomaszx.kulasek@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1457607478-2184-3-git-send-email-tomaszx.kulasek@intel.com",
    "date": "2016-03-10T10:57:58",
    "name": "[dpdk-dev,v3,2/2] examples: rework to use buffered tx",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "aebaf5ae31c640845c99c39ca6cc60660e4cc221",
    "submitter": {
        "id": 155,
        "url": "http://patches.dpdk.org/api/people/155/?format=api",
        "name": "Tomasz Kulasek",
        "email": "tomaszx.kulasek@intel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1457607478-2184-3-git-send-email-tomaszx.kulasek@intel.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/11386/comments/",
    "check": "pending",
    "checks": "http://patches.dpdk.org/api/patches/11386/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 3759F2B97;\n\tThu, 10 Mar 2016 11:59:35 +0100 (CET)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby dpdk.org (Postfix) with ESMTP id 2088829D2\n\tfor <dev@dpdk.org>; Thu, 10 Mar 2016 11:59:31 +0100 (CET)",
            "from fmsmga002.fm.intel.com ([10.253.24.26])\n\tby orsmga101.jf.intel.com with ESMTP; 10 Mar 2016 02:59:32 -0800",
            "from unknown (HELO Sent) ([10.217.248.141])\n\tby fmsmga002.fm.intel.com with SMTP; 10 Mar 2016 02:59:30 -0800",
            "by Sent (sSMTP sendmail emulation); Thu, 10 Mar 2016 11:59:07 +0100"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.24,315,1455004800\"; d=\"scan'208\";a=\"933754754\"",
        "From": "Tomasz Kulasek <tomaszx.kulasek@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Thu, 10 Mar 2016 11:57:58 +0100",
        "Message-Id": "<1457607478-2184-3-git-send-email-tomaszx.kulasek@intel.com>",
        "X-Mailer": "git-send-email 2.1.4",
        "In-Reply-To": "<1457607478-2184-1-git-send-email-tomaszx.kulasek@intel.com>",
        "References": "<1456333729-3804-1-git-send-email-tomaszx.kulasek@intel.com>\n\t<1457607478-2184-1-git-send-email-tomaszx.kulasek@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v3 2/2] examples: rework to use buffered tx",
        "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": "The internal buffering of packets for TX in sample apps is no longer\nneeded, so this patchset also replaces this code with calls to the new\nrte_eth_tx_buffer* APIs in:\n\n* l2fwd-jobstats\n* l2fwd-keepalive\n* l2fwd\n* l3fwd-acl\n* l3fwd-power\n* link_status_interrupt\n* client_server_mp\n* l2fwd_fork\n* packet_ordering\n* qos_meter\n\nv3 changes\n - updated due to the change of callback name\n\nv2 changes\n - rework synced with tx buffer API changes\n\nSigned-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>\n---\n examples/l2fwd-jobstats/main.c                     |  104 +++++++----------\n examples/l2fwd-keepalive/main.c                    |  100 ++++++----------\n examples/l2fwd/main.c                              |  104 +++++++----------\n examples/l3fwd-acl/main.c                          |   92 ++++++---------\n examples/l3fwd-power/main.c                        |   89 ++++++--------\n examples/link_status_interrupt/main.c              |  107 +++++++----------\n .../client_server_mp/mp_client/client.c            |  101 +++++++++-------\n examples/multi_process/l2fwd_fork/main.c           |   97 +++++++---------\n examples/packet_ordering/main.c                    |  122 ++++++++++++++------\n examples/qos_meter/main.c                          |   61 +++-------\n 10 files changed, 436 insertions(+), 541 deletions(-)",
    "diff": "diff --git a/examples/l2fwd-jobstats/main.c b/examples/l2fwd-jobstats/main.c\nindex 6da60e0..d1e9bf7 100644\n--- a/examples/l2fwd-jobstats/main.c\n+++ b/examples/l2fwd-jobstats/main.c\n@@ -1,7 +1,7 @@\n /*-\n  *   BSD LICENSE\n  *\n- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.\n+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n  *   All rights reserved.\n  *\n  *   Redistribution and use in source and binary forms, with or without\n@@ -41,6 +41,7 @@\n #include <rte_alarm.h>\n #include <rte_common.h>\n #include <rte_log.h>\n+#include <rte_malloc.h>\n #include <rte_memory.h>\n #include <rte_memcpy.h>\n #include <rte_memzone.h>\n@@ -97,18 +98,12 @@ static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];\n \n static unsigned int l2fwd_rx_queue_per_lcore = 1;\n \n-struct mbuf_table {\n-\tuint64_t next_flush_time;\n-\tunsigned len;\n-\tstruct rte_mbuf *mbufs[MAX_PKT_BURST];\n-};\n-\n #define MAX_RX_QUEUE_PER_LCORE 16\n #define MAX_TX_QUEUE_PER_PORT 16\n struct lcore_queue_conf {\n \tunsigned n_rx_port;\n \tunsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];\n-\tstruct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];\n+\tuint64_t next_flush_time[RTE_MAX_ETHPORTS];\n \n \tstruct rte_timer rx_timers[MAX_RX_QUEUE_PER_LCORE];\n \tstruct rte_jobstats port_fwd_jobs[MAX_RX_QUEUE_PER_LCORE];\n@@ -123,6 +118,8 @@ struct lcore_queue_conf {\n } __rte_cache_aligned;\n struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];\n \n+struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];\n+\n static const struct rte_eth_conf port_conf = {\n \t.rxmode = {\n \t\t.split_hdr_size = 0,\n@@ -373,59 +370,14 @@ show_stats_cb(__rte_unused void *param)\n \trte_eal_alarm_set(timer_period * US_PER_S, show_stats_cb, NULL);\n }\n \n-/* Send the burst of packets on an output interface */\n-static void\n-l2fwd_send_burst(struct lcore_queue_conf *qconf, uint8_t port)\n-{\n-\tstruct mbuf_table *m_table;\n-\tuint16_t ret;\n-\tuint16_t queueid = 0;\n-\tuint16_t n;\n-\n-\tm_table = &qconf->tx_mbufs[port];\n-\tn = m_table->len;\n-\n-\tm_table->next_flush_time = rte_get_timer_cycles() + drain_tsc;\n-\tm_table->len = 0;\n-\n-\tret = rte_eth_tx_burst(port, queueid, m_table->mbufs, n);\n-\n-\tport_statistics[port].tx += ret;\n-\tif (unlikely(ret < n)) {\n-\t\tport_statistics[port].dropped += (n - ret);\n-\t\tdo {\n-\t\t\trte_pktmbuf_free(m_table->mbufs[ret]);\n-\t\t} while (++ret < n);\n-\t}\n-}\n-\n-/* Enqueue packets for TX and prepare them to be sent */\n-static int\n-l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)\n-{\n-\tconst unsigned lcore_id = rte_lcore_id();\n-\tstruct lcore_queue_conf *qconf = &lcore_queue_conf[lcore_id];\n-\tstruct mbuf_table *m_table = &qconf->tx_mbufs[port];\n-\tuint16_t len = qconf->tx_mbufs[port].len;\n-\n-\tm_table->mbufs[len] = m;\n-\n-\tlen++;\n-\tm_table->len = len;\n-\n-\t/* Enough pkts to be sent. */\n-\tif (unlikely(len == MAX_PKT_BURST))\n-\t\tl2fwd_send_burst(qconf, port);\n-\n-\treturn 0;\n-}\n-\n static void\n l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)\n {\n \tstruct ether_hdr *eth;\n \tvoid *tmp;\n+\tint sent;\n \tunsigned dst_port;\n+\tstruct rte_eth_dev_tx_buffer *buffer;\n \n \tdst_port = l2fwd_dst_ports[portid];\n \teth = rte_pktmbuf_mtod(m, struct ether_hdr *);\n@@ -437,7 +389,10 @@ l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)\n \t/* src addr */\n \tether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);\n \n-\tl2fwd_send_packet(m, (uint8_t) dst_port);\n+\tbuffer = tx_buffer[dst_port];\n+\tsent = rte_eth_tx_buffer(dst_port, 0, buffer, m);\n+\tif (sent)\n+\t\tport_statistics[dst_port].tx += sent;\n }\n \n static void\n@@ -511,8 +466,10 @@ l2fwd_flush_job(__rte_unused struct rte_timer *timer, __rte_unused void *arg)\n \tuint64_t now;\n \tunsigned lcore_id;\n \tstruct lcore_queue_conf *qconf;\n-\tstruct mbuf_table *m_table;\n \tuint8_t portid;\n+\tunsigned i;\n+\tuint32_t sent;\n+\tstruct rte_eth_dev_tx_buffer *buffer;\n \n \tlcore_id = rte_lcore_id();\n \tqconf = &lcore_queue_conf[lcore_id];\n@@ -522,14 +479,20 @@ l2fwd_flush_job(__rte_unused struct rte_timer *timer, __rte_unused void *arg)\n \tnow = rte_get_timer_cycles();\n \tlcore_id = rte_lcore_id();\n \tqconf = &lcore_queue_conf[lcore_id];\n-\tfor (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {\n-\t\tm_table = &qconf->tx_mbufs[portid];\n-\t\tif (m_table->len == 0 || m_table->next_flush_time <= now)\n+\n+\tfor (i = 0; i < qconf->n_rx_port; i++) {\n+\t\tportid = l2fwd_dst_ports[qconf->rx_port_list[i]];\n+\n+\t\tif (qconf->next_flush_time[portid] <= now)\n \t\t\tcontinue;\n \n-\t\tl2fwd_send_burst(qconf, portid);\n-\t}\n+\t\tbuffer = tx_buffer[portid];\n+\t\tsent = rte_eth_tx_buffer_flush(portid, 0, buffer);\n+\t\tif (sent)\n+\t\t\tport_statistics[portid].tx += sent;\n \n+\t\tqconf->next_flush_time[portid] = rte_get_timer_cycles() + drain_tsc;\n+\t}\n \n \t/* Pass target to indicate that this job is happy of time interwal\n \t * in which it was called. */\n@@ -945,6 +908,23 @@ main(int argc, char **argv)\n \t\t\trte_exit(EXIT_FAILURE, \"rte_eth_tx_queue_setup:err=%d, port=%u\\n\",\n \t\t\t\tret, (unsigned) portid);\n \n+\t\t/* Initialize TX buffers */\n+\t\ttx_buffer[portid] = rte_zmalloc_socket(\"tx_buffer\",\n+\t\t\t\tRTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,\n+\t\t\t\trte_eth_dev_socket_id(portid));\n+\t\tif (tx_buffer[portid] == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot allocate buffer for tx on port %u\\n\",\n+\t\t\t\t\t(unsigned) portid);\n+\n+\t\trte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);\n+\n+\t\tret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],\n+\t\t\t\trte_eth_tx_buffer_count_callback,\n+\t\t\t\t&port_statistics[portid].dropped);\n+\t\tif (ret < 0)\n+\t\t\t\trte_exit(EXIT_FAILURE, \"Cannot set error callback for \"\n+\t\t\t\t\t\t\"tx buffer on port %u\\n\", (unsigned) portid);\n+\n \t\t/* Start device */\n \t\tret = rte_eth_dev_start(portid);\n \t\tif (ret < 0)\ndiff --git a/examples/l2fwd-keepalive/main.c b/examples/l2fwd-keepalive/main.c\nindex f4d52f2..94b8677 100644\n--- a/examples/l2fwd-keepalive/main.c\n+++ b/examples/l2fwd-keepalive/main.c\n@@ -1,7 +1,7 @@\n /*-\n  *   BSD LICENSE\n  *\n- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.\n+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n  *   All rights reserved.\n  *\n  *   Redistribution and use in source and binary forms, with or without\n@@ -47,6 +47,7 @@\n \n #include <rte_common.h>\n #include <rte_log.h>\n+#include <rte_malloc.h>\n #include <rte_memory.h>\n #include <rte_memcpy.h>\n #include <rte_memzone.h>\n@@ -97,21 +98,16 @@ static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];\n \n static unsigned int l2fwd_rx_queue_per_lcore = 1;\n \n-struct mbuf_table {\n-\tunsigned len;\n-\tstruct rte_mbuf *m_table[MAX_PKT_BURST];\n-};\n-\n #define MAX_RX_QUEUE_PER_LCORE 16\n #define MAX_TX_QUEUE_PER_PORT 16\n struct lcore_queue_conf {\n \tunsigned n_rx_port;\n \tunsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];\n-\tstruct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];\n-\n } __rte_cache_aligned;\n struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];\n \n+struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];\n+\n static const struct rte_eth_conf port_conf = {\n \t.rxmode = {\n \t\t.split_hdr_size = 0,\n@@ -192,58 +188,14 @@ print_stats(__attribute__((unused)) struct rte_timer *ptr_timer,\n \tprintf(\"\\n====================================================\\n\");\n }\n \n-/* Send the burst of packets on an output interface */\n-static int\n-l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)\n-{\n-\tstruct rte_mbuf **m_table;\n-\tunsigned ret;\n-\tunsigned queueid = 0;\n-\n-\tm_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;\n-\n-\tret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);\n-\tport_statistics[port].tx += ret;\n-\tif (unlikely(ret < n)) {\n-\t\tport_statistics[port].dropped += (n - ret);\n-\t\tdo {\n-\t\t\trte_pktmbuf_free(m_table[ret]);\n-\t\t} while (++ret < n);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-/* Enqueue packets for TX and prepare them to be sent */\n-static int\n-l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)\n-{\n-\tunsigned lcore_id, len;\n-\tstruct lcore_queue_conf *qconf;\n-\n-\tlcore_id = rte_lcore_id();\n-\n-\tqconf = &lcore_queue_conf[lcore_id];\n-\tlen = qconf->tx_mbufs[port].len;\n-\tqconf->tx_mbufs[port].m_table[len] = m;\n-\tlen++;\n-\n-\t/* enough pkts to be sent */\n-\tif (unlikely(len == MAX_PKT_BURST)) {\n-\t\tl2fwd_send_burst(qconf, MAX_PKT_BURST, port);\n-\t\tlen = 0;\n-\t}\n-\n-\tqconf->tx_mbufs[port].len = len;\n-\treturn 0;\n-}\n-\n static void\n l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)\n {\n \tstruct ether_hdr *eth;\n \tvoid *tmp;\n+\tint sent;\n \tunsigned dst_port;\n+\tstruct rte_eth_dev_tx_buffer *buffer;\n \n \tdst_port = l2fwd_dst_ports[portid];\n \teth = rte_pktmbuf_mtod(m, struct ether_hdr *);\n@@ -255,7 +207,10 @@ l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)\n \t/* src addr */\n \tether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);\n \n-\tl2fwd_send_packet(m, (uint8_t) dst_port);\n+\tbuffer = tx_buffer[dst_port];\n+\tsent = rte_eth_tx_buffer(dst_port, 0, buffer, m);\n+\tif (sent)\n+\t\tport_statistics[dst_port].tx += sent;\n }\n \n /* main processing loop */\n@@ -264,12 +219,14 @@ l2fwd_main_loop(void)\n {\n \tstruct rte_mbuf *pkts_burst[MAX_PKT_BURST];\n \tstruct rte_mbuf *m;\n+\tint sent;\n \tunsigned lcore_id;\n \tuint64_t prev_tsc, diff_tsc, cur_tsc;\n \tunsigned i, j, portid, nb_rx;\n \tstruct lcore_queue_conf *qconf;\n \tconst uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1)\n \t\t/ US_PER_S * BURST_TX_DRAIN_US;\n+\tstruct rte_eth_dev_tx_buffer *buffer;\n \n \tprev_tsc = 0;\n \n@@ -312,13 +269,15 @@ l2fwd_main_loop(void)\n \t\tdiff_tsc = cur_tsc - prev_tsc;\n \t\tif (unlikely(diff_tsc > drain_tsc)) {\n \n-\t\t\tfor (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {\n-\t\t\t\tif (qconf->tx_mbufs[portid].len == 0)\n-\t\t\t\t\tcontinue;\n-\t\t\t\tl2fwd_send_burst(&lcore_queue_conf[lcore_id],\n-\t\t\t\t\t\t qconf->tx_mbufs[portid].len,\n-\t\t\t\t\t\t (uint8_t) portid);\n-\t\t\t\tqconf->tx_mbufs[portid].len = 0;\n+\t\t\tfor (i = 0; i < qconf->n_rx_port; i++) {\n+\n+\t\t\t\tportid = l2fwd_dst_ports[qconf->rx_port_list[i]];\n+\t\t\t\tbuffer = tx_buffer[portid];\n+\n+\t\t\t\tsent = rte_eth_tx_buffer_flush(portid, 0, buffer);\n+\t\t\t\tif (sent)\n+\t\t\t\t\tport_statistics[portid].tx += sent;\n+\n \t\t\t}\n \n \t\t\tprev_tsc = cur_tsc;\n@@ -713,6 +672,23 @@ main(int argc, char **argv)\n \t\t\t\t\"rte_eth_tx_queue_setup:err=%d, port=%u\\n\",\n \t\t\t\tret, (unsigned) portid);\n \n+\t\t/* Initialize TX buffers */\n+\t\ttx_buffer[portid] = rte_zmalloc_socket(\"tx_buffer\",\n+\t\t\t\tRTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,\n+\t\t\t\trte_eth_dev_socket_id(portid));\n+\t\tif (tx_buffer[portid] == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot allocate buffer for tx on port %u\\n\",\n+\t\t\t\t\t(unsigned) portid);\n+\n+\t\trte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);\n+\n+\t\tret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],\n+\t\t\t\trte_eth_tx_buffer_count_callback,\n+\t\t\t\t&port_statistics[portid].dropped);\n+\t\tif (ret < 0)\n+\t\t\t\trte_exit(EXIT_FAILURE, \"Cannot set error callback for \"\n+\t\t\t\t\t\t\"tx buffer on port %u\\n\", (unsigned) portid);\n+\n \t\t/* Start device */\n \t\tret = rte_eth_dev_start(portid);\n \t\tif (ret < 0)\ndiff --git a/examples/l2fwd/main.c b/examples/l2fwd/main.c\nindex f35d8a1..e175681 100644\n--- a/examples/l2fwd/main.c\n+++ b/examples/l2fwd/main.c\n@@ -1,7 +1,7 @@\n /*-\n  *   BSD LICENSE\n  *\n- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n  *   All rights reserved.\n  *\n  *   Redistribution and use in source and binary forms, with or without\n@@ -49,6 +49,7 @@\n \n #include <rte_common.h>\n #include <rte_log.h>\n+#include <rte_malloc.h>\n #include <rte_memory.h>\n #include <rte_memcpy.h>\n #include <rte_memzone.h>\n@@ -99,21 +100,16 @@ static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];\n \n static unsigned int l2fwd_rx_queue_per_lcore = 1;\n \n-struct mbuf_table {\n-\tunsigned len;\n-\tstruct rte_mbuf *m_table[MAX_PKT_BURST];\n-};\n-\n #define MAX_RX_QUEUE_PER_LCORE 16\n #define MAX_TX_QUEUE_PER_PORT 16\n struct lcore_queue_conf {\n \tunsigned n_rx_port;\n \tunsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];\n-\tstruct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];\n-\n } __rte_cache_aligned;\n struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];\n \n+static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];\n+\n static const struct rte_eth_conf port_conf = {\n \t.rxmode = {\n \t\t.split_hdr_size = 0,\n@@ -189,58 +185,14 @@ print_stats(void)\n \tprintf(\"\\n====================================================\\n\");\n }\n \n-/* Send the burst of packets on an output interface */\n-static int\n-l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)\n-{\n-\tstruct rte_mbuf **m_table;\n-\tunsigned ret;\n-\tunsigned queueid =0;\n-\n-\tm_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;\n-\n-\tret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);\n-\tport_statistics[port].tx += ret;\n-\tif (unlikely(ret < n)) {\n-\t\tport_statistics[port].dropped += (n - ret);\n-\t\tdo {\n-\t\t\trte_pktmbuf_free(m_table[ret]);\n-\t\t} while (++ret < n);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-/* Enqueue packets for TX and prepare them to be sent */\n-static int\n-l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)\n-{\n-\tunsigned lcore_id, len;\n-\tstruct lcore_queue_conf *qconf;\n-\n-\tlcore_id = rte_lcore_id();\n-\n-\tqconf = &lcore_queue_conf[lcore_id];\n-\tlen = qconf->tx_mbufs[port].len;\n-\tqconf->tx_mbufs[port].m_table[len] = m;\n-\tlen++;\n-\n-\t/* enough pkts to be sent */\n-\tif (unlikely(len == MAX_PKT_BURST)) {\n-\t\tl2fwd_send_burst(qconf, MAX_PKT_BURST, port);\n-\t\tlen = 0;\n-\t}\n-\n-\tqconf->tx_mbufs[port].len = len;\n-\treturn 0;\n-}\n-\n static void\n l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)\n {\n \tstruct ether_hdr *eth;\n \tvoid *tmp;\n \tunsigned dst_port;\n+\tint sent;\n+\tstruct rte_eth_dev_tx_buffer *buffer;\n \n \tdst_port = l2fwd_dst_ports[portid];\n \teth = rte_pktmbuf_mtod(m, struct ether_hdr *);\n@@ -252,7 +204,10 @@ l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)\n \t/* src addr */\n \tether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);\n \n-\tl2fwd_send_packet(m, (uint8_t) dst_port);\n+\tbuffer = tx_buffer[dst_port];\n+\tsent = rte_eth_tx_buffer(dst_port, 0, buffer, m);\n+\tif (sent)\n+\t\tport_statistics[dst_port].tx += sent;\n }\n \n /* main processing loop */\n@@ -261,11 +216,14 @@ l2fwd_main_loop(void)\n {\n \tstruct rte_mbuf *pkts_burst[MAX_PKT_BURST];\n \tstruct rte_mbuf *m;\n+\tint sent;\n \tunsigned lcore_id;\n \tuint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;\n \tunsigned i, j, portid, nb_rx;\n \tstruct lcore_queue_conf *qconf;\n-\tconst uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;\n+\tconst uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *\n+\t\t\tBURST_TX_DRAIN_US;\n+\tstruct rte_eth_dev_tx_buffer *buffer;\n \n \tprev_tsc = 0;\n \ttimer_tsc = 0;\n@@ -285,6 +243,7 @@ l2fwd_main_loop(void)\n \t\tportid = qconf->rx_port_list[i];\n \t\tRTE_LOG(INFO, L2FWD, \" -- lcoreid=%u portid=%u\\n\", lcore_id,\n \t\t\tportid);\n+\n \t}\n \n \twhile (!force_quit) {\n@@ -297,13 +256,15 @@ l2fwd_main_loop(void)\n \t\tdiff_tsc = cur_tsc - prev_tsc;\n \t\tif (unlikely(diff_tsc > drain_tsc)) {\n \n-\t\t\tfor (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {\n-\t\t\t\tif (qconf->tx_mbufs[portid].len == 0)\n-\t\t\t\t\tcontinue;\n-\t\t\t\tl2fwd_send_burst(&lcore_queue_conf[lcore_id],\n-\t\t\t\t\t\t qconf->tx_mbufs[portid].len,\n-\t\t\t\t\t\t (uint8_t) portid);\n-\t\t\t\tqconf->tx_mbufs[portid].len = 0;\n+\t\t\tfor (i = 0; i < qconf->n_rx_port; i++) {\n+\n+\t\t\t\tportid = l2fwd_dst_ports[qconf->rx_port_list[i]];\n+\t\t\t\tbuffer = tx_buffer[portid];\n+\n+\t\t\t\tsent = rte_eth_tx_buffer_flush(portid, 0, buffer);\n+\t\t\t\tif (sent)\n+\t\t\t\t\tport_statistics[portid].tx += sent;\n+\n \t\t\t}\n \n \t\t\t/* if timer is enabled */\n@@ -688,6 +649,23 @@ main(int argc, char **argv)\n \t\t\trte_exit(EXIT_FAILURE, \"rte_eth_tx_queue_setup:err=%d, port=%u\\n\",\n \t\t\t\tret, (unsigned) portid);\n \n+\t\t/* Initialize TX buffers */\n+\t\ttx_buffer[portid] = rte_zmalloc_socket(\"tx_buffer\",\n+\t\t\t\tRTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,\n+\t\t\t\trte_eth_dev_socket_id(portid));\n+\t\tif (tx_buffer[portid] == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot allocate buffer for tx on port %u\\n\",\n+\t\t\t\t\t(unsigned) portid);\n+\n+\t\trte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);\n+\n+\t\tret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],\n+\t\t\t\trte_eth_tx_buffer_count_callback,\n+\t\t\t\t&port_statistics[portid].dropped);\n+\t\tif (ret < 0)\n+\t\t\t\trte_exit(EXIT_FAILURE, \"Cannot set error callback for \"\n+\t\t\t\t\t\t\"tx buffer on port %u\\n\", (unsigned) portid);\n+\n \t\t/* Start device */\n \t\tret = rte_eth_dev_start(portid);\n \t\tif (ret < 0)\ndiff --git a/examples/l3fwd-acl/main.c b/examples/l3fwd-acl/main.c\nindex f676d14..3a895b7 100644\n--- a/examples/l3fwd-acl/main.c\n+++ b/examples/l3fwd-acl/main.c\n@@ -1,7 +1,7 @@\n /*-\n  *   BSD LICENSE\n  *\n- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n  *   All rights reserved.\n  *\n  *   Redistribution and use in source and binary forms, with or without\n@@ -119,11 +119,6 @@ static uint32_t enabled_port_mask;\n static int promiscuous_on; /**< Ports set in promiscuous mode off by default. */\n static int numa_on = 1; /**< NUMA is enabled by default. */\n \n-struct mbuf_table {\n-\tuint16_t len;\n-\tstruct rte_mbuf *m_table[MAX_PKT_BURST];\n-};\n-\n struct lcore_rx_queue {\n \tuint8_t port_id;\n \tuint8_t queue_id;\n@@ -187,7 +182,7 @@ static struct rte_mempool *pktmbuf_pool[NB_SOCKETS];\n static inline int\n is_valid_ipv4_pkt(struct ipv4_hdr *pkt, uint32_t link_len);\n #endif\n-static inline int\n+static inline void\n send_single_packet(struct rte_mbuf *m, uint8_t port);\n \n #define MAX_ACL_RULE_NUM\t100000\n@@ -1291,56 +1286,26 @@ app_acl_init(void)\n struct lcore_conf {\n \tuint16_t n_rx_queue;\n \tstruct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE];\n+\tuint16_t n_tx_port;\n+\tuint16_t tx_port_id[RTE_MAX_ETHPORTS];\n \tuint16_t tx_queue_id[RTE_MAX_ETHPORTS];\n-\tstruct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];\n+\tstruct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];\n } __rte_cache_aligned;\n \n static struct lcore_conf lcore_conf[RTE_MAX_LCORE];\n \n-/* Send burst of packets on an output interface */\n-static inline int\n-send_burst(struct lcore_conf *qconf, uint16_t n, uint8_t port)\n-{\n-\tstruct rte_mbuf **m_table;\n-\tint ret;\n-\tuint16_t queueid;\n-\n-\tqueueid = qconf->tx_queue_id[port];\n-\tm_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;\n-\n-\tret = rte_eth_tx_burst(port, queueid, m_table, n);\n-\tif (unlikely(ret < n)) {\n-\t\tdo {\n-\t\t\trte_pktmbuf_free(m_table[ret]);\n-\t\t} while (++ret < n);\n-\t}\n-\n-\treturn 0;\n-}\n-\n /* Enqueue a single packet, and send burst if queue is filled */\n-static inline int\n+static inline void\n send_single_packet(struct rte_mbuf *m, uint8_t port)\n {\n \tuint32_t lcore_id;\n-\tuint16_t len;\n \tstruct lcore_conf *qconf;\n \n \tlcore_id = rte_lcore_id();\n \n \tqconf = &lcore_conf[lcore_id];\n-\tlen = qconf->tx_mbufs[port].len;\n-\tqconf->tx_mbufs[port].m_table[len] = m;\n-\tlen++;\n-\n-\t/* enough pkts to be sent */\n-\tif (unlikely(len == MAX_PKT_BURST)) {\n-\t\tsend_burst(qconf, MAX_PKT_BURST, port);\n-\t\tlen = 0;\n-\t}\n-\n-\tqconf->tx_mbufs[port].len = len;\n-\treturn 0;\n+\trte_eth_tx_buffer(port, qconf->tx_queue_id[port],\n+\t\t\tqconf->tx_buffer[port], m);\n }\n \n #ifdef DO_RFC_1812_CHECKS\n@@ -1428,20 +1393,12 @@ main_loop(__attribute__((unused)) void *dummy)\n \t\t */\n \t\tdiff_tsc = cur_tsc - prev_tsc;\n \t\tif (unlikely(diff_tsc > drain_tsc)) {\n-\n-\t\t\t/*\n-\t\t\t * This could be optimized (use queueid instead of\n-\t\t\t * portid), but it is not called so often\n-\t\t\t */\n-\t\t\tfor (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {\n-\t\t\t\tif (qconf->tx_mbufs[portid].len == 0)\n-\t\t\t\t\tcontinue;\n-\t\t\t\tsend_burst(&lcore_conf[lcore_id],\n-\t\t\t\t\tqconf->tx_mbufs[portid].len,\n-\t\t\t\t\tportid);\n-\t\t\t\tqconf->tx_mbufs[portid].len = 0;\n+\t\t\tfor (i = 0; i < qconf->n_tx_port; ++i) {\n+\t\t\t\tportid = qconf->tx_port_id[i];\n+\t\t\t\trte_eth_tx_buffer_flush(portid,\n+\t\t\t\t\t\tqconf->tx_queue_id[portid],\n+\t\t\t\t\t\tqconf->tx_buffer[portid]);\n \t\t\t}\n-\n \t\t\tprev_tsc = cur_tsc;\n \t\t}\n \n@@ -1936,6 +1893,7 @@ main(int argc, char **argv)\n \tunsigned lcore_id;\n \tuint32_t n_tx_queue, nb_lcores;\n \tuint8_t portid, nb_rx_queue, queue, socketid;\n+\tuint8_t nb_tx_port;\n \n \t/* init EAL */\n \tret = rte_eal_init(argc, argv);\n@@ -1968,6 +1926,7 @@ main(int argc, char **argv)\n \t\trte_exit(EXIT_FAILURE, \"app_acl_init failed\\n\");\n \n \tnb_lcores = rte_lcore_count();\n+\tnb_tx_port = 0;\n \n \t/* initialize all ports */\n \tfor (portid = 0; portid < nb_ports; portid++) {\n@@ -2003,6 +1962,22 @@ main(int argc, char **argv)\n \t\tif (ret < 0)\n \t\t\trte_exit(EXIT_FAILURE, \"init_mem failed\\n\");\n \n+\t\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n+\t\t\tif (rte_lcore_is_enabled(lcore_id) == 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\t/* Initialize TX buffers */\n+\t\t\tqconf = &lcore_conf[lcore_id];\n+\t\t\tqconf->tx_buffer[portid] = rte_zmalloc_socket(\"tx_buffer\",\n+\t\t\t\t\tRTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,\n+\t\t\t\t\trte_eth_dev_socket_id(portid));\n+\t\t\tif (qconf->tx_buffer[portid] == NULL)\n+\t\t\t\trte_exit(EXIT_FAILURE, \"Can't allocate tx buffer for port %u\\n\",\n+\t\t\t\t\t\t(unsigned) portid);\n+\n+\t\t\trte_eth_tx_buffer_init(qconf->tx_buffer[portid], MAX_PKT_BURST);\n+\t\t}\n+\n \t\t/* init one TX queue per couple (lcore,port) */\n \t\tqueueid = 0;\n \t\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n@@ -2032,8 +2007,13 @@ main(int argc, char **argv)\n \t\t\tqconf = &lcore_conf[lcore_id];\n \t\t\tqconf->tx_queue_id[portid] = queueid;\n \t\t\tqueueid++;\n+\n+\t\t\tqconf->n_tx_port = nb_tx_port;\n+\t\t\tqconf->tx_port_id[qconf->n_tx_port] = portid;\n \t\t}\n \t\tprintf(\"\\n\");\n+\n+\t\tnb_tx_port++;\n \t}\n \n \tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\ndiff --git a/examples/l3fwd-power/main.c b/examples/l3fwd-power/main.c\nindex 828c18a..2ed106b 100644\n--- a/examples/l3fwd-power/main.c\n+++ b/examples/l3fwd-power/main.c\n@@ -1,7 +1,7 @@\n /*-\n  *   BSD LICENSE\n  *\n- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n  *   All rights reserved.\n  *\n  *   Redistribution and use in source and binary forms, with or without\n@@ -47,6 +47,7 @@\n #include <rte_common.h>\n #include <rte_byteorder.h>\n #include <rte_log.h>\n+#include <rte_malloc.h>\n #include <rte_memory.h>\n #include <rte_memcpy.h>\n #include <rte_memzone.h>\n@@ -173,11 +174,6 @@ enum freq_scale_hint_t\n \tFREQ_HIGHEST  =       2\n };\n \n-struct mbuf_table {\n-\tuint16_t len;\n-\tstruct rte_mbuf *m_table[MAX_PKT_BURST];\n-};\n-\n struct lcore_rx_queue {\n \tuint8_t port_id;\n \tuint8_t queue_id;\n@@ -347,8 +343,10 @@ static lookup_struct_t *ipv4_l3fwd_lookup_struct[NB_SOCKETS];\n struct lcore_conf {\n \tuint16_t n_rx_queue;\n \tstruct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE];\n+\tuint16_t n_tx_port;\n+\tuint16_t tx_port_id[RTE_MAX_ETHPORTS];\n \tuint16_t tx_queue_id[RTE_MAX_ETHPORTS];\n-\tstruct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];\n+\tstruct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];\n \tlookup_struct_t * ipv4_lookup_struct;\n \tlookup_struct_t * ipv6_lookup_struct;\n } __rte_cache_aligned;\n@@ -442,49 +440,19 @@ power_timer_cb(__attribute__((unused)) struct rte_timer *tim,\n \tstats[lcore_id].sleep_time = 0;\n }\n \n-/* Send burst of packets on an output interface */\n-static inline int\n-send_burst(struct lcore_conf *qconf, uint16_t n, uint8_t port)\n-{\n-\tstruct rte_mbuf **m_table;\n-\tint ret;\n-\tuint16_t queueid;\n-\n-\tqueueid = qconf->tx_queue_id[port];\n-\tm_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;\n-\n-\tret = rte_eth_tx_burst(port, queueid, m_table, n);\n-\tif (unlikely(ret < n)) {\n-\t\tdo {\n-\t\t\trte_pktmbuf_free(m_table[ret]);\n-\t\t} while (++ret < n);\n-\t}\n-\n-\treturn 0;\n-}\n-\n /* Enqueue a single packet, and send burst if queue is filled */\n static inline int\n send_single_packet(struct rte_mbuf *m, uint8_t port)\n {\n \tuint32_t lcore_id;\n-\tuint16_t len;\n \tstruct lcore_conf *qconf;\n \n \tlcore_id = rte_lcore_id();\n-\n \tqconf = &lcore_conf[lcore_id];\n-\tlen = qconf->tx_mbufs[port].len;\n-\tqconf->tx_mbufs[port].m_table[len] = m;\n-\tlen++;\n-\n-\t/* enough pkts to be sent */\n-\tif (unlikely(len == MAX_PKT_BURST)) {\n-\t\tsend_burst(qconf, MAX_PKT_BURST, port);\n-\t\tlen = 0;\n-\t}\n \n-\tqconf->tx_mbufs[port].len = len;\n+\trte_eth_tx_buffer(port, qconf->tx_queue_id[port],\n+\t\t\tqconf->tx_buffer[port], m);\n+\n \treturn 0;\n }\n \n@@ -905,20 +873,12 @@ main_loop(__attribute__((unused)) void *dummy)\n \t\t */\n \t\tdiff_tsc = cur_tsc - prev_tsc;\n \t\tif (unlikely(diff_tsc > drain_tsc)) {\n-\n-\t\t\t/*\n-\t\t\t * This could be optimized (use queueid instead of\n-\t\t\t * portid), but it is not called so often\n-\t\t\t */\n-\t\t\tfor (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {\n-\t\t\t\tif (qconf->tx_mbufs[portid].len == 0)\n-\t\t\t\t\tcontinue;\n-\t\t\t\tsend_burst(&lcore_conf[lcore_id],\n-\t\t\t\t\tqconf->tx_mbufs[portid].len,\n-\t\t\t\t\tportid);\n-\t\t\t\tqconf->tx_mbufs[portid].len = 0;\n+\t\t\tfor (i = 0; i < qconf->n_tx_port; ++i) {\n+\t\t\t\tportid = qconf->tx_port_id[i];\n+\t\t\t\trte_eth_tx_buffer_flush(portid,\n+\t\t\t\t\t\tqconf->tx_queue_id[portid],\n+\t\t\t\t\t\tqconf->tx_buffer[portid]);\n \t\t\t}\n-\n \t\t\tprev_tsc = cur_tsc;\n \t\t}\n \n@@ -1579,6 +1539,7 @@ main(int argc, char **argv)\n \tuint32_t n_tx_queue, nb_lcores;\n \tuint32_t dev_rxq_num, dev_txq_num;\n \tuint8_t portid, nb_rx_queue, queue, socketid;\n+\tuint8_t nb_tx_port;\n \n \t/* catch SIGINT and restore cpufreq governor to ondemand */\n \tsignal(SIGINT, signal_exit_now);\n@@ -1614,6 +1575,7 @@ main(int argc, char **argv)\n \t\trte_exit(EXIT_FAILURE, \"check_port_config failed\\n\");\n \n \tnb_lcores = rte_lcore_count();\n+\tnb_tx_port = 0;\n \n \t/* initialize all ports */\n \tfor (portid = 0; portid < nb_ports; portid++) {\n@@ -1657,6 +1619,22 @@ main(int argc, char **argv)\n \t\tif (ret < 0)\n \t\t\trte_exit(EXIT_FAILURE, \"init_mem failed\\n\");\n \n+\t\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n+\t\t\tif (rte_lcore_is_enabled(lcore_id) == 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\t/* Initialize TX buffers */\n+\t\t\tqconf = &lcore_conf[lcore_id];\n+\t\t\tqconf->tx_buffer[portid] = rte_zmalloc_socket(\"tx_buffer\",\n+\t\t\t\tRTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,\n+\t\t\t\trte_eth_dev_socket_id(portid));\n+\t\t\tif (qconf->tx_buffer[portid] == NULL)\n+\t\t\t\trte_exit(EXIT_FAILURE, \"Can't allocate tx buffer for port %u\\n\",\n+\t\t\t\t\t\t(unsigned) portid);\n+\n+\t\t\trte_eth_tx_buffer_init(qconf->tx_buffer[portid], MAX_PKT_BURST);\n+\t\t}\n+\n \t\t/* init one TX queue per couple (lcore,port) */\n \t\tqueueid = 0;\n \t\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n@@ -1689,8 +1667,13 @@ main(int argc, char **argv)\n \t\t\tqconf = &lcore_conf[lcore_id];\n \t\t\tqconf->tx_queue_id[portid] = queueid;\n \t\t\tqueueid++;\n+\n+\t\t\tqconf->n_tx_port = nb_tx_port;\n+\t\t\tqconf->tx_port_id[qconf->n_tx_port] = portid;\n \t\t}\n \t\tprintf(\"\\n\");\n+\n+\t\tnb_tx_port++;\n \t}\n \n \tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\ndiff --git a/examples/link_status_interrupt/main.c b/examples/link_status_interrupt/main.c\nindex c57a08a..cbc29bc 100644\n--- a/examples/link_status_interrupt/main.c\n+++ b/examples/link_status_interrupt/main.c\n@@ -1,7 +1,7 @@\n /*-\n  *   BSD LICENSE\n  *\n- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n  *   All rights reserved.\n  *\n  *   Redistribution and use in source and binary forms, with or without\n@@ -48,6 +48,7 @@\n \n #include <rte_common.h>\n #include <rte_log.h>\n+#include <rte_malloc.h>\n #include <rte_memory.h>\n #include <rte_memcpy.h>\n #include <rte_memzone.h>\n@@ -97,10 +98,6 @@ static unsigned int lsi_rx_queue_per_lcore = 1;\n static unsigned lsi_dst_ports[RTE_MAX_ETHPORTS] = {0};\n \n #define MAX_PKT_BURST 32\n-struct mbuf_table {\n-\tunsigned len;\n-\tstruct rte_mbuf *m_table[MAX_PKT_BURST];\n-};\n \n #define MAX_RX_QUEUE_PER_LCORE 16\n #define MAX_TX_QUEUE_PER_PORT 16\n@@ -108,11 +105,11 @@ struct lcore_queue_conf {\n \tunsigned n_rx_port;\n \tunsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];\n \tunsigned tx_queue_id;\n-\tstruct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];\n-\n } __rte_cache_aligned;\n struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];\n \n+struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];\n+\n static const struct rte_eth_conf port_conf = {\n \t.rxmode = {\n \t\t.split_hdr_size = 0,\n@@ -202,59 +199,14 @@ print_stats(void)\n \tprintf(\"\\n====================================================\\n\");\n }\n \n-/* Send the packet on an output interface */\n-static int\n-lsi_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)\n-{\n-\tstruct rte_mbuf **m_table;\n-\tunsigned ret;\n-\tunsigned queueid;\n-\n-\tqueueid = (uint16_t) qconf->tx_queue_id;\n-\tm_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;\n-\n-\tret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);\n-\tport_statistics[port].tx += ret;\n-\tif (unlikely(ret < n)) {\n-\t\tport_statistics[port].dropped += (n - ret);\n-\t\tdo {\n-\t\t\trte_pktmbuf_free(m_table[ret]);\n-\t\t} while (++ret < n);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-/* Send the packet on an output interface */\n-static int\n-lsi_send_packet(struct rte_mbuf *m, uint8_t port)\n-{\n-\tunsigned lcore_id, len;\n-\tstruct lcore_queue_conf *qconf;\n-\n-\tlcore_id = rte_lcore_id();\n-\n-\tqconf = &lcore_queue_conf[lcore_id];\n-\tlen = qconf->tx_mbufs[port].len;\n-\tqconf->tx_mbufs[port].m_table[len] = m;\n-\tlen++;\n-\n-\t/* enough pkts to be sent */\n-\tif (unlikely(len == MAX_PKT_BURST)) {\n-\t\tlsi_send_burst(qconf, MAX_PKT_BURST, port);\n-\t\tlen = 0;\n-\t}\n-\n-\tqconf->tx_mbufs[port].len = len;\n-\treturn 0;\n-}\n-\n static void\n lsi_simple_forward(struct rte_mbuf *m, unsigned portid)\n {\n \tstruct ether_hdr *eth;\n \tvoid *tmp;\n \tunsigned dst_port = lsi_dst_ports[portid];\n+\tint sent;\n+\tstruct rte_eth_dev_tx_buffer *buffer;\n \n \teth = rte_pktmbuf_mtod(m, struct ether_hdr *);\n \n@@ -265,7 +217,10 @@ lsi_simple_forward(struct rte_mbuf *m, unsigned portid)\n \t/* src addr */\n \tether_addr_copy(&lsi_ports_eth_addr[dst_port], &eth->s_addr);\n \n-\tlsi_send_packet(m, (uint8_t) dst_port);\n+\tbuffer = tx_buffer[dst_port];\n+\tsent = rte_eth_tx_buffer(dst_port, 0, buffer, m);\n+\tif (sent)\n+\t\tport_statistics[dst_port].tx += sent;\n }\n \n /* main processing loop */\n@@ -275,10 +230,13 @@ lsi_main_loop(void)\n \tstruct rte_mbuf *pkts_burst[MAX_PKT_BURST];\n \tstruct rte_mbuf *m;\n \tunsigned lcore_id;\n+\tunsigned sent;\n \tuint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;\n \tunsigned i, j, portid, nb_rx;\n \tstruct lcore_queue_conf *qconf;\n-\tconst uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;\n+\tconst uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *\n+\t\t\tBURST_TX_DRAIN_US;\n+\tstruct rte_eth_dev_tx_buffer *buffer;\n \n \tprev_tsc = 0;\n \ttimer_tsc = 0;\n@@ -310,15 +268,15 @@ lsi_main_loop(void)\n \t\tdiff_tsc = cur_tsc - prev_tsc;\n \t\tif (unlikely(diff_tsc > drain_tsc)) {\n \n-\t\t\t/* this could be optimized (use queueid instead of\n-\t\t\t * portid), but it is not called so often */\n-\t\t\tfor (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {\n-\t\t\t\tif (qconf->tx_mbufs[portid].len == 0)\n-\t\t\t\t\tcontinue;\n-\t\t\t\tlsi_send_burst(&lcore_queue_conf[lcore_id],\n-\t\t\t\t\t\t qconf->tx_mbufs[portid].len,\n-\t\t\t\t\t\t (uint8_t) portid);\n-\t\t\t\tqconf->tx_mbufs[portid].len = 0;\n+\t\t\tfor (i = 0; i < qconf->n_rx_port; i++) {\n+\n+\t\t\t\tportid = lsi_dst_ports[qconf->rx_port_list[i]];\n+\t\t\t\tbuffer = tx_buffer[portid];\n+\n+\t\t\t\tsent = rte_eth_tx_buffer_flush(portid, 0, buffer);\n+\t\t\t\tif (sent)\n+\t\t\t\t\tport_statistics[portid].tx += sent;\n+\n \t\t\t}\n \n \t\t\t/* if timer is enabled */\n@@ -722,6 +680,23 @@ main(int argc, char **argv)\n \t\t\trte_exit(EXIT_FAILURE, \"rte_eth_tx_queue_setup: err=%d,port=%u\\n\",\n \t\t\t\t  ret, (unsigned) portid);\n \n+\t\t/* Initialize TX buffers */\n+\t\ttx_buffer[portid] = rte_zmalloc_socket(\"tx_buffer\",\n+\t\t\t\tRTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,\n+\t\t\t\trte_eth_dev_socket_id(portid));\n+\t\tif (tx_buffer[portid] == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot allocate buffer for tx on port %u\\n\",\n+\t\t\t\t\t(unsigned) portid);\n+\n+\t\trte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);\n+\n+\t\tret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],\n+\t\t\t\trte_eth_tx_buffer_count_callback,\n+\t\t\t\t&port_statistics[portid].dropped);\n+\t\tif (ret < 0)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot set error callback for \"\n+\t\t\t\t\t\"tx buffer on port %u\\n\", (unsigned) portid);\n+\n \t\t/* Start device */\n \t\tret = rte_eth_dev_start(portid);\n \t\tif (ret < 0)\n@@ -729,6 +704,8 @@ main(int argc, char **argv)\n \t\t\t\t  ret, (unsigned) portid);\n \t\tprintf(\"done:\\n\");\n \n+\t\trte_eth_promiscuous_enable(portid);\n+\n \t\tprintf(\"Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\\n\\n\",\n \t\t\t\t(unsigned) portid,\n \t\t\t\tlsi_ports_eth_addr[portid].addr_bytes[0],\ndiff --git a/examples/multi_process/client_server_mp/mp_client/client.c b/examples/multi_process/client_server_mp/mp_client/client.c\nindex bf049a4..d4f9ca3 100644\n--- a/examples/multi_process/client_server_mp/mp_client/client.c\n+++ b/examples/multi_process/client_server_mp/mp_client/client.c\n@@ -1,7 +1,7 @@\n /*-\n  *   BSD LICENSE\n  *\n- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n  *   All rights reserved.\n  *\n  *   Redistribution and use in source and binary forms, with or without\n@@ -42,6 +42,7 @@\n #include <string.h>\n \n #include <rte_common.h>\n+#include <rte_malloc.h>\n #include <rte_memory.h>\n #include <rte_memzone.h>\n #include <rte_eal.h>\n@@ -72,17 +73,13 @@\n  * queue to write to. */\n static uint8_t client_id = 0;\n \n-struct mbuf_queue {\n #define MBQ_CAPACITY 32\n-\tstruct rte_mbuf *bufs[MBQ_CAPACITY];\n-\tuint16_t top;\n-};\n \n /* maps input ports to output ports for packets */\n static uint8_t output_ports[RTE_MAX_ETHPORTS];\n \n /* buffers up a set of packet that are ready to send */\n-static struct mbuf_queue output_bufs[RTE_MAX_ETHPORTS];\n+struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];\n \n /* shared data from server. We update statistics here */\n static volatile struct tx_stats *tx_stats;\n@@ -149,11 +146,51 @@ parse_app_args(int argc, char *argv[])\n }\n \n /*\n+ * Tx buffer error callback\n+ */\n+static void\n+flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count,\n+\t\tvoid *userdata) {\n+\tint i;\n+\tuint8_t port_id = (uintptr_t)userdata;\n+\n+\ttx_stats->tx_drop[port_id] += count;\n+\n+\t/* free the mbufs which failed from transmit */\n+\tfor (i = 0; i < count; i++)\n+\t\trte_pktmbuf_free(unsent[i]);\n+\n+}\n+\n+static void\n+configure_tx_buffer(uint8_t port_id, uint16_t size)\n+{\n+\tint ret;\n+\n+\t/* Initialize TX buffers */\n+\ttx_buffer[port_id] = rte_zmalloc_socket(\"tx_buffer\",\n+\t\t\tRTE_ETH_TX_BUFFER_SIZE(size), 0,\n+\t\t\trte_eth_dev_socket_id(port_id));\n+\tif (tx_buffer[port_id] == NULL)\n+\t\trte_exit(EXIT_FAILURE, \"Cannot allocate buffer for tx on port %u\\n\",\n+\t\t\t\t(unsigned) port_id);\n+\n+\trte_eth_tx_buffer_init(tx_buffer[port_id], size);\n+\n+\tret = rte_eth_tx_buffer_set_err_callback(tx_buffer[port_id],\n+\t\t\tflush_tx_error_callback, (void *)(intptr_t)port_id);\n+\tif (ret < 0)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot set error callback for \"\n+\t\t\t\t\t\"tx buffer on port %u\\n\", (unsigned) port_id);\n+}\n+\n+/*\n  * set up output ports so that all traffic on port gets sent out\n  * its paired port. Index using actual port numbers since that is\n  * what comes in the mbuf structure.\n  */\n-static void configure_output_ports(const struct port_info *ports)\n+static void\n+configure_output_ports(const struct port_info *ports)\n {\n \tint i;\n \tif (ports->num_ports > RTE_MAX_ETHPORTS)\n@@ -164,41 +201,11 @@ static void configure_output_ports(const struct port_info *ports)\n \t\tuint8_t p2 = ports->id[i+1];\n \t\toutput_ports[p1] = p2;\n \t\toutput_ports[p2] = p1;\n-\t}\n-}\n \n+\t\tconfigure_tx_buffer(p1, MBQ_CAPACITY);\n+\t\tconfigure_tx_buffer(p2, MBQ_CAPACITY);\n \n-static inline void\n-send_packets(uint8_t port)\n-{\n-\tuint16_t i, sent;\n-\tstruct mbuf_queue *mbq = &output_bufs[port];\n-\n-\tif (unlikely(mbq->top == 0))\n-\t\treturn;\n-\n-\tsent = rte_eth_tx_burst(port, client_id, mbq->bufs, mbq->top);\n-\tif (unlikely(sent < mbq->top)){\n-\t\tfor (i = sent; i < mbq->top; i++)\n-\t\t\trte_pktmbuf_free(mbq->bufs[i]);\n-\t\ttx_stats->tx_drop[port] += (mbq->top - sent);\n \t}\n-\ttx_stats->tx[port] += sent;\n-\tmbq->top = 0;\n-}\n-\n-/*\n- * Enqueue a packet to be sent on a particular port, but\n- * don't send it yet. Only when the buffer is full.\n- */\n-static inline void\n-enqueue_packet(struct rte_mbuf *buf, uint8_t port)\n-{\n-\tstruct mbuf_queue *mbq = &output_bufs[port];\n-\tmbq->bufs[mbq->top++] = buf;\n-\n-\tif (mbq->top == MBQ_CAPACITY)\n-\t\tsend_packets(port);\n }\n \n /*\n@@ -209,10 +216,15 @@ enqueue_packet(struct rte_mbuf *buf, uint8_t port)\n static void\n handle_packet(struct rte_mbuf *buf)\n {\n+\tint sent;\n \tconst uint8_t in_port = buf->port;\n \tconst uint8_t out_port = output_ports[in_port];\n+\tstruct rte_eth_dev_tx_buffer *buffer = tx_buffer[out_port];\n+\n+\tsent = rte_eth_tx_buffer(out_port, client_id, buffer, buf);\n+\tif (sent)\n+\t\ttx_stats->tx[out_port] += sent;\n \n-\tenqueue_packet(buf, out_port);\n }\n \n /*\n@@ -229,6 +241,7 @@ main(int argc, char *argv[])\n \tint need_flush = 0; /* indicates whether we have unsent packets */\n \tint retval;\n \tvoid *pkts[PKT_READ_SIZE];\n+\tuint16_t sent;\n \n \tif ((retval = rte_eal_init(argc, argv)) < 0)\n \t\treturn -1;\n@@ -274,8 +287,12 @@ main(int argc, char *argv[])\n \n \t\tif (unlikely(rx_pkts == 0)){\n \t\t\tif (need_flush)\n-\t\t\t\tfor (port = 0; port < ports->num_ports; port++)\n-\t\t\t\t\tsend_packets(ports->id[port]);\n+\t\t\t\tfor (port = 0; port < ports->num_ports; port++) {\n+\t\t\t\t\tsent = rte_eth_tx_buffer_flush(ports->id[port], client_id,\n+\t\t\t\t\t\t\ttx_buffer[port]);\n+\t\t\t\t\tif (unlikely(sent))\n+\t\t\t\t\t\ttx_stats->tx[port] += sent;\n+\t\t\t\t}\n \t\t\tneed_flush = 0;\n \t\t\tcontinue;\n \t\t}\ndiff --git a/examples/multi_process/l2fwd_fork/main.c b/examples/multi_process/l2fwd_fork/main.c\nindex f2d7eab..aebf531 100644\n--- a/examples/multi_process/l2fwd_fork/main.c\n+++ b/examples/multi_process/l2fwd_fork/main.c\n@@ -1,7 +1,7 @@\n /*-\n  *   BSD LICENSE\n  *\n- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n  *   All rights reserved.\n  *\n  *   Redistribution and use in source and binary forms, with or without\n@@ -127,11 +127,11 @@ struct mbuf_table {\n struct lcore_queue_conf {\n \tunsigned n_rx_port;\n \tunsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];\n-\tstruct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];\n-\n } __rte_cache_aligned;\n struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];\n \n+struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];\n+\n struct lcore_resource_struct {\n \tint enabled;\t/* Only set in case this lcore involved into packet forwarding */\n \tint flags; \t    /* Set only slave need to restart or recreate */\n@@ -583,58 +583,14 @@ slave_exit_cb(unsigned slaveid, __attribute__((unused))int stat)\n \trte_spinlock_unlock(&res_lock);\n }\n \n-/* Send the packet on an output interface */\n-static int\n-l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)\n-{\n-\tstruct rte_mbuf **m_table;\n-\tunsigned ret;\n-\tunsigned queueid =0;\n-\n-\tm_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;\n-\n-\tret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);\n-\tport_statistics[port].tx += ret;\n-\tif (unlikely(ret < n)) {\n-\t\tport_statistics[port].dropped += (n - ret);\n-\t\tdo {\n-\t\t\trte_pktmbuf_free(m_table[ret]);\n-\t\t} while (++ret < n);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-/* Send the packet on an output interface */\n-static int\n-l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)\n-{\n-\tunsigned lcore_id, len;\n-\tstruct lcore_queue_conf *qconf;\n-\n-\tlcore_id = rte_lcore_id();\n-\n-\tqconf = &lcore_queue_conf[lcore_id];\n-\tlen = qconf->tx_mbufs[port].len;\n-\tqconf->tx_mbufs[port].m_table[len] = m;\n-\tlen++;\n-\n-\t/* enough pkts to be sent */\n-\tif (unlikely(len == MAX_PKT_BURST)) {\n-\t\tl2fwd_send_burst(qconf, MAX_PKT_BURST, port);\n-\t\tlen = 0;\n-\t}\n-\n-\tqconf->tx_mbufs[port].len = len;\n-\treturn 0;\n-}\n-\n static void\n l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)\n {\n \tstruct ether_hdr *eth;\n \tvoid *tmp;\n \tunsigned dst_port;\n+\tint sent;\n+\tstruct rte_eth_dev_tx_buffer *buffer;\n \n \tdst_port = l2fwd_dst_ports[portid];\n \teth = rte_pktmbuf_mtod(m, struct ether_hdr *);\n@@ -646,7 +602,10 @@ l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)\n \t/* src addr */\n \tether_addr_copy(&l2fwd_ports_eth_addr[dst_port], &eth->s_addr);\n \n-\tl2fwd_send_packet(m, (uint8_t) dst_port);\n+\tbuffer = tx_buffer[dst_port];\n+\tsent = rte_eth_tx_buffer(dst_port, 0, buffer, m);\n+\tif (sent)\n+\t\tport_statistics[dst_port].tx += sent;\n }\n \n /* main processing loop */\n@@ -655,11 +614,14 @@ l2fwd_main_loop(void)\n {\n \tstruct rte_mbuf *pkts_burst[MAX_PKT_BURST];\n \tstruct rte_mbuf *m;\n+\tint sent;\n \tunsigned lcore_id;\n \tuint64_t prev_tsc, diff_tsc, cur_tsc;\n \tunsigned i, j, portid, nb_rx;\n \tstruct lcore_queue_conf *qconf;\n-\tconst uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;\n+\tconst uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *\n+\t\t\tBURST_TX_DRAIN_US;\n+\tstruct rte_eth_dev_tx_buffer *buffer;\n \n \tprev_tsc = 0;\n \n@@ -699,13 +661,15 @@ l2fwd_main_loop(void)\n \t\tdiff_tsc = cur_tsc - prev_tsc;\n \t\tif (unlikely(diff_tsc > drain_tsc)) {\n \n-\t\t\tfor (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {\n-\t\t\t\tif (qconf->tx_mbufs[portid].len == 0)\n-\t\t\t\t\tcontinue;\n-\t\t\t\tl2fwd_send_burst(&lcore_queue_conf[lcore_id],\n-\t\t\t\t\t\t qconf->tx_mbufs[portid].len,\n-\t\t\t\t\t\t (uint8_t) portid);\n-\t\t\t\tqconf->tx_mbufs[portid].len = 0;\n+\t\t\tfor (i = 0; i < qconf->n_rx_port; i++) {\n+\n+\t\t\t\tportid = l2fwd_dst_ports[qconf->rx_port_list[i]];\n+\t\t\t\tbuffer = tx_buffer[portid];\n+\n+\t\t\t\tsent = rte_eth_tx_buffer_flush(portid, 0, buffer);\n+\t\t\t\tif (sent)\n+\t\t\t\t\tport_statistics[portid].tx += sent;\n+\n \t\t\t}\n \t\t}\n \n@@ -1144,6 +1108,23 @@ main(int argc, char **argv)\n \t\t\trte_exit(EXIT_FAILURE, \"rte_eth_tx_queue_setup:err=%d, port=%u\\n\",\n \t\t\t\tret, (unsigned) portid);\n \n+\t\t/* Initialize TX buffers */\n+\t\ttx_buffer[portid] = rte_zmalloc_socket(\"tx_buffer\",\n+\t\t\t\tRTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,\n+\t\t\t\trte_eth_dev_socket_id(portid));\n+\t\tif (tx_buffer[portid] == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot allocate buffer for tx on port %u\\n\",\n+\t\t\t\t\t(unsigned) portid);\n+\n+\t\trte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);\n+\n+\t\tret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],\n+\t\t\t\trte_eth_tx_buffer_count_callback,\n+\t\t\t\t&port_statistics[portid].dropped);\n+\t\tif (ret < 0)\n+\t\t\t\trte_exit(EXIT_FAILURE, \"Cannot set error callback for \"\n+\t\t\t\t\t\t\"tx buffer on port %u\\n\", (unsigned) portid);\n+\n \t\t/* Start device */\n \t\tret = rte_eth_dev_start(portid);\n \t\tif (ret < 0)\ndiff --git a/examples/packet_ordering/main.c b/examples/packet_ordering/main.c\nindex 1d9a86f..15bb900 100644\n--- a/examples/packet_ordering/main.c\n+++ b/examples/packet_ordering/main.c\n@@ -1,7 +1,7 @@\n /*-\n  *   BSD LICENSE\n  *\n- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n  *   All rights reserved.\n  *\n  *   Redistribution and use in source and binary forms, with or without\n@@ -39,6 +39,7 @@\n #include <rte_errno.h>\n #include <rte_ethdev.h>\n #include <rte_lcore.h>\n+#include <rte_malloc.h>\n #include <rte_mbuf.h>\n #include <rte_mempool.h>\n #include <rte_ring.h>\n@@ -54,7 +55,7 @@\n \n #define RING_SIZE 16384\n \n-/* uncommnet below line to enable debug logs */\n+/* uncomment below line to enable debug logs */\n /* #define DEBUG */\n \n #ifdef DEBUG\n@@ -86,11 +87,6 @@ struct send_thread_args {\n \tstruct rte_reorder_buffer *buffer;\n };\n \n-struct output_buffer {\n-\tunsigned count;\n-\tstruct rte_mbuf *mbufs[MAX_PKTS_BURST];\n-};\n-\n volatile struct app_stats {\n \tstruct {\n \t\tuint64_t rx_pkts;\n@@ -235,6 +231,68 @@ parse_args(int argc, char **argv)\n \treturn 0;\n }\n \n+/*\n+ * Tx buffer error callback\n+ */\n+static void\n+flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count,\n+\t\tvoid *userdata __rte_unused) {\n+\n+\t/* free the mbufs which failed from transmit */\n+\tapp_stats.tx.ro_tx_failed_pkts += count;\n+\tLOG_DEBUG(REORDERAPP, \"%s:Packet loss with tx_burst\\n\", __func__);\n+\tpktmbuf_free_bulk(unsent, count);\n+\n+}\n+\n+static inline int\n+free_tx_buffers(struct rte_eth_dev_tx_buffer *tx_buffer[]) {\n+\tconst uint8_t nb_ports = rte_eth_dev_count();\n+\tunsigned port_id;\n+\n+\t/* initialize buffers for all ports */\n+\tfor (port_id = 0; port_id < nb_ports; port_id++) {\n+\t\t/* skip ports that are not enabled */\n+\t\tif ((portmask & (1 << port_id)) == 0)\n+\t\t\tcontinue;\n+\n+\t\trte_free(tx_buffer[port_id]);\n+\t}\n+\treturn 0;\n+}\n+\n+static inline int\n+configure_tx_buffers(struct rte_eth_dev_tx_buffer *tx_buffer[])\n+{\n+\tconst uint8_t nb_ports = rte_eth_dev_count();\n+\tunsigned port_id;\n+\tint ret;\n+\n+\t/* initialize buffers for all ports */\n+\tfor (port_id = 0; port_id < nb_ports; port_id++) {\n+\t\t/* skip ports that are not enabled */\n+\t\tif ((portmask & (1 << port_id)) == 0)\n+\t\t\tcontinue;\n+\n+\t\t/* Initialize TX buffers */\n+\t\ttx_buffer[port_id] = rte_zmalloc_socket(\"tx_buffer\",\n+\t\t\t\tRTE_ETH_TX_BUFFER_SIZE(MAX_PKTS_BURST), 0,\n+\t\t\t\trte_eth_dev_socket_id(port_id));\n+\t\tif (tx_buffer[port_id] == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot allocate buffer for tx on port %u\\n\",\n+\t\t\t\t\t(unsigned) port_id);\n+\n+\t\trte_eth_tx_buffer_init(tx_buffer[port_id], MAX_PKTS_BURST);\n+\n+\t\tret = rte_eth_tx_buffer_set_err_callback(tx_buffer[port_id],\n+\t\t\t\tflush_tx_error_callback, NULL);\n+\t\tif (ret < 0)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot set error callback for \"\n+\t\t\t\t\t\"tx buffer on port %u\\n\", (unsigned) port_id);\n+\t}\n+\treturn 0;\n+}\n+\n static inline int\n configure_eth_port(uint8_t port_id)\n {\n@@ -438,22 +496,6 @@ worker_thread(void *args_ptr)\n \treturn 0;\n }\n \n-static inline void\n-flush_one_port(struct output_buffer *outbuf, uint8_t outp)\n-{\n-\tunsigned nb_tx = rte_eth_tx_burst(outp, 0, outbuf->mbufs,\n-\t\t\toutbuf->count);\n-\tapp_stats.tx.ro_tx_pkts += nb_tx;\n-\n-\tif (unlikely(nb_tx < outbuf->count)) {\n-\t\t/* free the mbufs which failed from transmit */\n-\t\tapp_stats.tx.ro_tx_failed_pkts += (outbuf->count - nb_tx);\n-\t\tLOG_DEBUG(REORDERAPP, \"%s:Packet loss with tx_burst\\n\", __func__);\n-\t\tpktmbuf_free_bulk(&outbuf->mbufs[nb_tx], outbuf->count - nb_tx);\n-\t}\n-\toutbuf->count = 0;\n-}\n-\n /**\n  * Dequeue mbufs from the workers_to_tx ring and reorder them before\n  * transmitting.\n@@ -465,12 +507,15 @@ send_thread(struct send_thread_args *args)\n \tunsigned int i, dret;\n \tuint16_t nb_dq_mbufs;\n \tuint8_t outp;\n-\tstatic struct output_buffer tx_buffers[RTE_MAX_ETHPORTS];\n+\tunsigned sent;\n \tstruct rte_mbuf *mbufs[MAX_PKTS_BURST];\n \tstruct rte_mbuf *rombufs[MAX_PKTS_BURST] = {NULL};\n+\tstatic struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];\n \n \tRTE_LOG(INFO, REORDERAPP, \"%s() started on lcore %u\\n\", __func__, rte_lcore_id());\n \n+\tconfigure_tx_buffers(tx_buffer);\n+\n \twhile (!quit_signal) {\n \n \t\t/* deque the mbufs from workers_to_tx ring */\n@@ -515,7 +560,7 @@ send_thread(struct send_thread_args *args)\n \t\tdret = rte_reorder_drain(args->buffer, rombufs, MAX_PKTS_BURST);\n \t\tfor (i = 0; i < dret; i++) {\n \n-\t\t\tstruct output_buffer *outbuf;\n+\t\t\tstruct rte_eth_dev_tx_buffer *outbuf;\n \t\t\tuint8_t outp1;\n \n \t\t\toutp1 = rombufs[i]->port;\n@@ -525,12 +570,15 @@ send_thread(struct send_thread_args *args)\n \t\t\t\tcontinue;\n \t\t\t}\n \n-\t\t\toutbuf = &tx_buffers[outp1];\n-\t\t\toutbuf->mbufs[outbuf->count++] = rombufs[i];\n-\t\t\tif (outbuf->count == MAX_PKTS_BURST)\n-\t\t\t\tflush_one_port(outbuf, outp1);\n+\t\t\toutbuf = tx_buffer[outp1];\n+\t\t\tsent = rte_eth_tx_buffer(outp1, 0, outbuf, rombufs[i]);\n+\t\t\tif (sent)\n+\t\t\t\tapp_stats.tx.ro_tx_pkts += sent;\n \t\t}\n \t}\n+\n+\tfree_tx_buffers(tx_buffer);\n+\n \treturn 0;\n }\n \n@@ -542,12 +590,16 @@ tx_thread(struct rte_ring *ring_in)\n {\n \tuint32_t i, dqnum;\n \tuint8_t outp;\n-\tstatic struct output_buffer tx_buffers[RTE_MAX_ETHPORTS];\n+\tunsigned sent;\n \tstruct rte_mbuf *mbufs[MAX_PKTS_BURST];\n-\tstruct output_buffer *outbuf;\n+\tstruct rte_eth_dev_tx_buffer *outbuf;\n+\tstatic struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];\n \n \tRTE_LOG(INFO, REORDERAPP, \"%s() started on lcore %u\\n\", __func__,\n \t\t\t\t\t\t\trte_lcore_id());\n+\n+\tconfigure_tx_buffers(tx_buffer);\n+\n \twhile (!quit_signal) {\n \n \t\t/* deque the mbufs from workers_to_tx ring */\n@@ -567,10 +619,10 @@ tx_thread(struct rte_ring *ring_in)\n \t\t\t\tcontinue;\n \t\t\t}\n \n-\t\t\toutbuf = &tx_buffers[outp];\n-\t\t\toutbuf->mbufs[outbuf->count++] = mbufs[i];\n-\t\t\tif (outbuf->count == MAX_PKTS_BURST)\n-\t\t\t\tflush_one_port(outbuf, outp);\n+\t\t\toutbuf = tx_buffer[outp];\n+\t\t\tsent = rte_eth_tx_buffer(outp, 0, outbuf, mbufs[i]);\n+\t\t\tif (sent)\n+\t\t\t\tapp_stats.tx.ro_tx_pkts += sent;\n \t\t}\n \t}\n \ndiff --git a/examples/qos_meter/main.c b/examples/qos_meter/main.c\nindex 0de5e7f..b968b00 100644\n--- a/examples/qos_meter/main.c\n+++ b/examples/qos_meter/main.c\n@@ -1,7 +1,7 @@\n /*-\n  *   BSD LICENSE\n  *\n- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n  *   All rights reserved.\n  *\n  *   Redistribution and use in source and binary forms, with or without\n@@ -36,6 +36,7 @@\n \n #include <rte_common.h>\n #include <rte_eal.h>\n+#include <rte_malloc.h>\n #include <rte_mempool.h>\n #include <rte_ethdev.h>\n #include <rte_cycles.h>\n@@ -118,9 +119,7 @@ static struct rte_eth_conf port_conf = {\n static uint8_t port_rx;\n static uint8_t port_tx;\n static struct rte_mbuf *pkts_rx[PKT_RX_BURST_MAX];\n-static struct rte_mbuf *pkts_tx[PKT_TX_BURST_MAX];\n-static uint16_t pkts_tx_len = 0;\n-\n+struct rte_eth_dev_tx_buffer *tx_buffer;\n \n struct rte_meter_srtcm_params app_srtcm_params[] = {\n \t{.cir = 1000000 * 46,  .cbs = 2048, .ebs = 2048},\n@@ -188,27 +187,8 @@ main_loop(__attribute__((unused)) void *dummy)\n \t\tcurrent_time = rte_rdtsc();\n \t\ttime_diff = current_time - last_time;\n \t\tif (unlikely(time_diff > TIME_TX_DRAIN)) {\n-\t\t\tint ret;\n-\n-\t\t\tif (pkts_tx_len == 0) {\n-\t\t\t\tlast_time = current_time;\n-\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\n-\t\t\t/* Write packet burst to NIC TX */\n-\t\t\tret = rte_eth_tx_burst(port_tx, NIC_TX_QUEUE, pkts_tx, pkts_tx_len);\n-\n-\t\t\t/* Free buffers for any packets not written successfully */\n-\t\t\tif (unlikely(ret < pkts_tx_len)) {\n-\t\t\t\tfor ( ; ret < pkts_tx_len; ret ++) {\n-\t\t\t\t\trte_pktmbuf_free(pkts_tx[ret]);\n-\t\t\t\t}\n-\t\t\t}\n-\n-\t\t\t/* Empty the output buffer */\n-\t\t\tpkts_tx_len = 0;\n-\n+\t\t\t/* Flush tx buffer */\n+\t\t\trte_eth_tx_buffer_flush(port_tx, NIC_TX_QUEUE, tx_buffer);\n \t\t\tlast_time = current_time;\n \t\t}\n \n@@ -222,26 +202,8 @@ main_loop(__attribute__((unused)) void *dummy)\n \t\t\t/* Handle current packet */\n \t\t\tif (app_pkt_handle(pkt, current_time) == DROP)\n \t\t\t\trte_pktmbuf_free(pkt);\n-\t\t\telse {\n-\t\t\t\tpkts_tx[pkts_tx_len] = pkt;\n-\t\t\t\tpkts_tx_len ++;\n-\t\t\t}\n-\n-\t\t\t/* Write packets from output buffer to NIC TX when full burst is available */\n-\t\t\tif (unlikely(pkts_tx_len == PKT_TX_BURST_MAX)) {\n-\t\t\t\t/* Write packet burst to NIC TX */\n-\t\t\t\tint ret = rte_eth_tx_burst(port_tx, NIC_TX_QUEUE, pkts_tx, PKT_TX_BURST_MAX);\n-\n-\t\t\t\t/* Free buffers for any packets not written successfully */\n-\t\t\t\tif (unlikely(ret < PKT_TX_BURST_MAX)) {\n-\t\t\t\t\tfor ( ; ret < PKT_TX_BURST_MAX; ret ++) {\n-\t\t\t\t\t\trte_pktmbuf_free(pkts_tx[ret]);\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\n-\t\t\t\t/* Empty the output buffer */\n-\t\t\t\tpkts_tx_len = 0;\n-\t\t\t}\n+\t\t\telse\n+\t\t\t\trte_eth_tx_buffer(port_tx, NIC_TX_QUEUE, tx_buffer, pkt);\n \t\t}\n \t}\n }\n@@ -397,6 +359,15 @@ main(int argc, char **argv)\n \tif (ret < 0)\n \t\trte_exit(EXIT_FAILURE, \"Port %d TX queue setup error (%d)\\n\", port_tx, ret);\n \n+\ttx_buffer = rte_zmalloc_socket(\"tx_buffer\",\n+\t\t\tRTE_ETH_TX_BUFFER_SIZE(PKT_TX_BURST_MAX), 0,\n+\t\t\trte_eth_dev_socket_id(port_tx));\n+\tif (tx_buffer == NULL)\n+\t\trte_exit(EXIT_FAILURE, \"Port %d TX buffer allocation error\\n\",\n+\t\t\t\tport_tx);\n+\n+\trte_eth_tx_buffer_init(tx_buffer, PKT_TX_BURST_MAX);\n+\n \tret = rte_eth_dev_start(port_rx);\n \tif (ret < 0)\n \t\trte_exit(EXIT_FAILURE, \"Port %d start error (%d)\\n\", port_rx, ret);\n",
    "prefixes": [
        "dpdk-dev",
        "v3",
        "2/2"
    ]
}