get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 8789,
    "url": "http://patches.dpdk.org/api/patches/8789/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1447060816-9923-2-git-send-email-konstantin.ananyev@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": "<1447060816-9923-2-git-send-email-konstantin.ananyev@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1447060816-9923-2-git-send-email-konstantin.ananyev@intel.com",
    "date": "2015-11-09T09:20:15",
    "name": "[dpdk-dev,PATCHv5,1/2] testpmd: add ability to split outgoing packets",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "b761af4fb4ebfaf012dcaf3f841aec806459c8fa",
    "submitter": {
        "id": 33,
        "url": "http://patches.dpdk.org/api/people/33/?format=api",
        "name": "Ananyev, Konstantin",
        "email": "konstantin.ananyev@intel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1447060816-9923-2-git-send-email-konstantin.ananyev@intel.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/8789/comments/",
    "check": "pending",
    "checks": "http://patches.dpdk.org/api/patches/8789/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 5FA4D5946;\n\tMon,  9 Nov 2015 10:20:49 +0100 (CET)",
            "from mga01.intel.com (mga01.intel.com [192.55.52.88])\n\tby dpdk.org (Postfix) with ESMTP id EB0D65424\n\tfor <dev@dpdk.org>; Mon,  9 Nov 2015 10:20:46 +0100 (CET)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n\tby fmsmga101.fm.intel.com with ESMTP; 09 Nov 2015 01:20:45 -0800",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga002.jf.intel.com with ESMTP; 09 Nov 2015 01:20:45 -0800",
            "from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com\n\t[10.237.217.45])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\ttA99KhXr025893; Mon, 9 Nov 2015 09:20:43 GMT",
            "from sivswdev01.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev01.ir.intel.com with ESMTP id tA99KhPV010192;\n\tMon, 9 Nov 2015 09:20:43 GMT",
            "(from kananye1@localhost)\n\tby sivswdev01.ir.intel.com with  id tA99KhQu010188;\n\tMon, 9 Nov 2015 09:20:43 GMT"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.20,265,1444719600\"; d=\"scan'208\";a=\"845939582\"",
        "From": "Konstantin Ananyev <konstantin.ananyev@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Mon,  9 Nov 2015 09:20:15 +0000",
        "Message-Id": "<1447060816-9923-2-git-send-email-konstantin.ananyev@intel.com>",
        "X-Mailer": "git-send-email 1.7.4.1",
        "In-Reply-To": "<1447060816-9923-1-git-send-email-konstantin.ananyev@intel.com>",
        "References": "<1447060816-9923-1-git-send-email-konstantin.ananyev@intel.com>",
        "Subject": "[dpdk-dev] [PATCHv5 1/2] testpmd: add ability to split outgoing\n\tpackets",
        "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": "For CSUM forwarding mode add ability to copy & split outgoing packet\ninto the new mbuf that consists of multiple segments.\nFor TXONLY and CSUM forwarding modes add ability to make number of\nsegments in the outgoing packet to vary on a per packet basis.\nNumber of segments and size of each segment is controlled by\n'set txpkts' command.\nSplit policy is controlled by 'set txsplit' command.\nPossible values are: on | off | rand.\nTha allows to increase test coverage for TX PMD codepaths.\n\nSigned-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>\n---\n app/test-pmd/cmdline.c                      |  57 +++++++++-\n app/test-pmd/config.c                       |  61 +++++++++++\n app/test-pmd/csumonly.c                     | 163 +++++++++++++++++++++++++++-\n app/test-pmd/testpmd.c                      |   3 +\n app/test-pmd/testpmd.h                      |  10 ++\n app/test-pmd/txonly.c                       |  13 ++-\n doc/guides/testpmd_app_ug/testpmd_funcs.rst |  11 +-\n 7 files changed, 309 insertions(+), 9 deletions(-)",
    "diff": "diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c\nindex c637198..a92fe0b 100644\n--- a/app/test-pmd/cmdline.c\n+++ b/app/test-pmd/cmdline.c\n@@ -199,7 +199,7 @@ static void cmd_help_long_parsed(void *parsed_result,\n \t\t\t\"clear port (info|stats|xstats|fdir|stat_qmap) (port_id|all)\\n\"\n \t\t\t\"    Clear information for port_id, or all.\\n\\n\"\n \n-\t\t\t\"show config (rxtx|cores|fwd)\\n\"\n+\t\t\t\"show config (rxtx|cores|fwd|txpkts)\\n\"\n \t\t\t\"    Display the given configuration.\\n\\n\"\n \n \t\t\t\"read rxd (port_id) (queue_id) (rxd_id)\\n\"\n@@ -246,7 +246,12 @@ static void cmd_help_long_parsed(void *parsed_result,\n \n \t\t\t\"set txpkts (x[,y]*)\\n\"\n \t\t\t\"    Set the length of each segment of TXONLY\"\n-\t\t\t\" packets.\\n\\n\"\n+\t\t\t\" and optionally CSUM packets.\\n\\n\"\n+\n+\t\t\t\"set txsplit (off|on|rand)\\n\"\n+\t\t\t\"    Set the split policy for the TX packets.\"\n+\t\t\t\" Right now only applicable for CSUM and TXONLY\"\n+\t\t\t\" modes\\n\\n\"\n \n \t\t\t\"set corelist (x[,y]*)\\n\"\n \t\t\t\"    Set the list of forwarding cores.\\n\\n\"\n@@ -2621,6 +2626,47 @@ cmdline_parse_inst_t cmd_set_txpkts = {\n \t},\n };\n \n+/* *** SET COPY AND SPLIT POLICY ON TX PACKETS *** */\n+\n+struct cmd_set_txsplit_result {\n+\tcmdline_fixed_string_t cmd_keyword;\n+\tcmdline_fixed_string_t txsplit;\n+\tcmdline_fixed_string_t mode;\n+};\n+\n+static void\n+cmd_set_txsplit_parsed(void *parsed_result,\n+\t\t      __attribute__((unused)) struct cmdline *cl,\n+\t\t      __attribute__((unused)) void *data)\n+{\n+\tstruct cmd_set_txsplit_result *res;\n+\n+\tres = parsed_result;\n+\tset_tx_pkt_split(res->mode);\n+}\n+\n+cmdline_parse_token_string_t cmd_set_txsplit_keyword =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_set_txsplit_result,\n+\t\t\t\t cmd_keyword, \"set\");\n+cmdline_parse_token_string_t cmd_set_txsplit_name =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_set_txsplit_result,\n+\t\t\t\t txsplit, \"txsplit\");\n+cmdline_parse_token_string_t cmd_set_txsplit_mode =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_set_txsplit_result,\n+\t\t\t\t mode, NULL);\n+\n+cmdline_parse_inst_t cmd_set_txsplit = {\n+\t.f = cmd_set_txsplit_parsed,\n+\t.data = NULL,\n+\t.help_str = \"set txsplit on|off|rand\",\n+\t.tokens = {\n+\t\t(void *)&cmd_set_txsplit_keyword,\n+\t\t(void *)&cmd_set_txsplit_name,\n+\t\t(void *)&cmd_set_txsplit_mode,\n+\t\tNULL,\n+\t},\n+};\n+\n /* *** ADD/REMOVE ALL VLAN IDENTIFIERS TO/FROM A PORT VLAN RX FILTER *** */\n struct cmd_rx_vlan_filter_all_result {\n \tcmdline_fixed_string_t rx_vlan;\n@@ -5233,6 +5279,8 @@ static void cmd_showcfg_parsed(void *parsed_result,\n \t\tfwd_lcores_config_display();\n \telse if (!strcmp(res->what, \"fwd\"))\n \t\tfwd_config_display();\n+\telse if (!strcmp(res->what, \"txpkts\"))\n+\t\tshow_tx_pkt_segments();\n }\n \n cmdline_parse_token_string_t cmd_showcfg_show =\n@@ -5241,12 +5289,12 @@ cmdline_parse_token_string_t cmd_showcfg_port =\n \tTOKEN_STRING_INITIALIZER(struct cmd_showcfg_result, cfg, \"config\");\n cmdline_parse_token_string_t cmd_showcfg_what =\n \tTOKEN_STRING_INITIALIZER(struct cmd_showcfg_result, what,\n-\t\t\t\t \"rxtx#cores#fwd\");\n+\t\t\t\t \"rxtx#cores#fwd#txpkts\");\n \n cmdline_parse_inst_t cmd_showcfg = {\n \t.f = cmd_showcfg_parsed,\n \t.data = NULL,\n-\t.help_str = \"show config rxtx|cores|fwd\",\n+\t.help_str = \"show config rxtx|cores|fwd|txpkts\",\n \t.tokens = {\n \t\t(void *)&cmd_showcfg_show,\n \t\t(void *)&cmd_showcfg_port,\n@@ -9574,6 +9622,7 @@ cmdline_parse_ctx_t main_ctx[] = {\n \t(cmdline_parse_inst_t *)&cmd_reset,\n \t(cmdline_parse_inst_t *)&cmd_set_numbers,\n \t(cmdline_parse_inst_t *)&cmd_set_txpkts,\n+\t(cmdline_parse_inst_t *)&cmd_set_txsplit,\n \t(cmdline_parse_inst_t *)&cmd_set_fwd_list,\n \t(cmdline_parse_inst_t *)&cmd_set_fwd_mask,\n \t(cmdline_parse_inst_t *)&cmd_set_fwd_mode,\ndiff --git a/app/test-pmd/config.c b/app/test-pmd/config.c\nindex 938b456..8ec7d83 100644\n--- a/app/test-pmd/config.c\n+++ b/app/test-pmd/config.c\n@@ -97,6 +97,24 @@\n \n static char *flowtype_to_str(uint16_t flow_type);\n \n+static const struct {\n+\tenum tx_pkt_split split;\n+\tconst char *name;\n+} tx_split_name[] = {\n+\t{\n+\t\t.split = TX_PKT_SPLIT_OFF,\n+\t\t.name = \"off\",\n+\t},\n+\t{\n+\t\t.split = TX_PKT_SPLIT_ON,\n+\t\t.name = \"on\",\n+\t},\n+\t{\n+\t\t.split = TX_PKT_SPLIT_RND,\n+\t\t.name = \"rand\",\n+\t},\n+};\n+\n struct rss_type_info {\n \tchar str[32];\n \tuint64_t rss_type;\n@@ -1582,6 +1600,49 @@ set_nb_pkt_per_burst(uint16_t nb)\n \t       (unsigned int) nb_pkt_per_burst);\n }\n \n+static const char *\n+tx_split_get_name(enum tx_pkt_split split)\n+{\n+\tuint32_t i;\n+\n+\tfor (i = 0; i != RTE_DIM(tx_split_name); i++) {\n+\t\tif (tx_split_name[i].split == split)\n+\t\t\treturn tx_split_name[i].name;\n+\t}\n+\treturn NULL;\n+}\n+\n+void\n+set_tx_pkt_split(const char *name)\n+{\n+\tuint32_t i;\n+\n+\tfor (i = 0; i != RTE_DIM(tx_split_name); i++) {\n+\t\tif (strcmp(tx_split_name[i].name, name) == 0) {\n+\t\t\ttx_pkt_split = tx_split_name[i].split;\n+\t\t\treturn;\n+\t\t}\n+\t}\n+\tprintf(\"unknown value: \\\"%s\\\"\\n\", name);\n+}\n+\n+void\n+show_tx_pkt_segments(void)\n+{\n+\tuint32_t i, n;\n+\tconst char *split;\n+\n+\tn = tx_pkt_nb_segs;\n+\tsplit = tx_split_get_name(tx_pkt_split);\n+\n+\tprintf(\"Number of segments: %u\\n\", n);\n+\tprintf(\"Segment sizes: \");\n+\tfor (i = 0; i != n - 1; i++)\n+\t\tprintf(\"%hu,\", tx_pkt_seg_lengths[i]);\n+\tprintf(\"%hu\\n\", tx_pkt_seg_lengths[i]);\n+\tprintf(\"Split packet: %s\\n\", split);\n+}\n+\n void\n set_tx_pkt_segments(unsigned *seg_lengths, unsigned nb_segs)\n {\ndiff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c\nindex c9c095d..7e4f662 100644\n--- a/app/test-pmd/csumonly.c\n+++ b/app/test-pmd/csumonly.c\n@@ -457,6 +457,155 @@ process_outer_cksums(void *outer_l3_hdr, struct testpmd_offload_info *info,\n }\n \n /*\n+ * Helper function.\n+ * Performs actual copying.\n+ * Returns number of segments in the destination mbuf on success,\n+ * or negative error code on failure.\n+ */\n+static int\n+mbuf_copy_split(const struct rte_mbuf *ms, struct rte_mbuf *md[],\n+\tuint16_t seglen[], uint8_t nb_seg)\n+{\n+\tuint32_t dlen, slen, tlen;\n+\tuint32_t i, len;\n+\tconst struct rte_mbuf *m;\n+\tconst uint8_t *src;\n+\tuint8_t *dst;\n+\n+\tdlen = 0;\n+\tslen = 0;\n+\ttlen = 0;\n+\n+\tdst = NULL;\n+\tsrc = NULL;\n+\n+\tm = ms;\n+\ti = 0;\n+\twhile (ms != NULL && i != nb_seg) {\n+\n+\t\tif (slen == 0) {\n+\t\t\tslen = rte_pktmbuf_data_len(ms);\n+\t\t\tsrc = rte_pktmbuf_mtod(ms, const uint8_t *);\n+\t\t}\n+\n+\t\tif (dlen == 0) {\n+\t\t\tdlen = RTE_MIN(seglen[i], slen);\n+\t\t\tmd[i]->data_len = dlen;\n+\t\t\tmd[i]->next = (i + 1 == nb_seg) ? NULL : md[i + 1];\n+\t\t\tdst = rte_pktmbuf_mtod(md[i], uint8_t *);\n+\t\t}\n+\n+\t\tlen = RTE_MIN(slen, dlen);\n+\t\tmemcpy(dst, src, len);\n+\t\ttlen += len;\n+\t\tslen -= len;\n+\t\tdlen -= len;\n+\t\tsrc += len;\n+\t\tdst += len;\n+\n+\t\tif (slen == 0)\n+\t\t\tms = ms->next;\n+\t\tif (dlen == 0)\n+\t\t\ti++;\n+\t}\n+\n+\tif (ms != NULL)\n+\t\treturn -ENOBUFS;\n+\telse if (tlen != m->pkt_len)\n+\t\treturn -EINVAL;\n+\n+\tmd[0]->nb_segs = nb_seg;\n+\tmd[0]->pkt_len = tlen;\n+\tmd[0]->vlan_tci = m->vlan_tci;\n+\tmd[0]->vlan_tci_outer = m->vlan_tci_outer;\n+\tmd[0]->ol_flags = m->ol_flags;\n+\tmd[0]->tx_offload = m->tx_offload;\n+\n+\treturn nb_seg;\n+}\n+\n+/*\n+ * Allocate a new mbuf with up to tx_pkt_nb_segs segments.\n+ * Copy packet contents and offload information into then new segmented mbuf.\n+ */\n+static struct rte_mbuf *\n+pkt_copy_split(const struct rte_mbuf *pkt)\n+{\n+\tint32_t n, rc;\n+\tuint32_t i, len, nb_seg;\n+\tstruct rte_mempool *mp;\n+\tuint16_t seglen[RTE_MAX_SEGS_PER_PKT];\n+\tstruct rte_mbuf *p, *md[RTE_MAX_SEGS_PER_PKT];\n+\n+\tmp = current_fwd_lcore()->mbp;\n+\n+\tif (tx_pkt_split == TX_PKT_SPLIT_RND)\n+\t\tnb_seg = random() % tx_pkt_nb_segs + 1;\n+\telse\n+\t\tnb_seg = tx_pkt_nb_segs;\n+\n+\tmemcpy(seglen, tx_pkt_seg_lengths, nb_seg * sizeof(seglen[0]));\n+\n+\t/* calculate number of segments to use and their length. */\n+\tlen = 0;\n+\tfor (i = 0; i != nb_seg && len < pkt->pkt_len; i++) {\n+\t\tlen += seglen[i];\n+\t\tmd[i] = NULL;\n+\t}\n+\n+\tn = pkt->pkt_len - len;\n+\n+\t/* update size of the last segment to fit rest of the packet */\n+\tif (n >= 0) {\n+\t\tseglen[i - 1] += n;\n+\t\tlen += n;\n+\t}\n+\n+\tnb_seg = i;\n+\twhile (i != 0) {\n+\t\tp = rte_pktmbuf_alloc(mp);\n+\t\tif (p == NULL) {\n+\t\t\tRTE_LOG(ERR, USER1,\n+\t\t\t\t\"failed to allocate %u-th of %u mbuf \"\n+\t\t\t\t\"from mempool: %s\\n\",\n+\t\t\t\tnb_seg - i, nb_seg, mp->name);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tmd[--i] = p;\n+\t\tif (rte_pktmbuf_tailroom(md[i]) < seglen[i]) {\n+\t\t\tRTE_LOG(ERR, USER1, \"mempool %s, %u-th segment: \"\n+\t\t\t\t\"expected seglen: %u, \"\n+\t\t\t\t\"actual mbuf tailroom: %u\\n\",\n+\t\t\t\tmp->name, i, seglen[i],\n+\t\t\t\trte_pktmbuf_tailroom(md[i]));\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\t/* all mbufs successfully allocated, do copy */\n+\tif (i == 0) {\n+\t\trc = mbuf_copy_split(pkt, md, seglen, nb_seg);\n+\t\tif (rc < 0)\n+\t\t\tRTE_LOG(ERR, USER1,\n+\t\t\t\t\"mbuf_copy_split for %p(len=%u, nb_seg=%hhu) \"\n+\t\t\t\t\"into %u segments failed with error code: %d\\n\",\n+\t\t\t\tpkt, pkt->pkt_len, pkt->nb_segs, nb_seg, rc);\n+\n+\t\t/* figure out how many mbufs to free. */\n+\t\ti = RTE_MAX(rc, 0);\n+\t}\n+\n+\t/* free unused mbufs */\n+\tfor (; i != nb_seg; i++) {\n+\t\trte_pktmbuf_free_seg(md[i]);\n+\t\tmd[i] = NULL;\n+\t}\n+\n+\treturn md[0];\n+}\n+\n+/*\n  * Receive a burst of packets, and for each packet:\n  *  - parse packet, and try to recognize a supported packet type (1)\n  *  - if it's not a supported packet type, don't touch the packet, else:\n@@ -486,7 +635,7 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)\n {\n \tstruct rte_mbuf *pkts_burst[MAX_PKT_BURST];\n \tstruct rte_port *txp;\n-\tstruct rte_mbuf *m;\n+\tstruct rte_mbuf *m, *p;\n \tstruct ether_hdr *eth_hdr;\n \tvoid *l3_hdr = NULL, *outer_l3_hdr = NULL; /* can be IPv4 or IPv6 */\n \tuint16_t nb_rx;\n@@ -627,6 +776,16 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)\n \t\tm->tso_segsz = info.tso_segsz;\n \t\tm->ol_flags = ol_flags;\n \n+\t\t/* Do split & copy for the packet. */\n+\t\tif (tx_pkt_split != TX_PKT_SPLIT_OFF) {\n+\t\t\tp = pkt_copy_split(m);\n+\t\t\tif (p != NULL) {\n+\t\t\t\trte_pktmbuf_free(m);\n+\t\t\t\tm = p;\n+\t\t\t\tpkts_burst[i] = m;\n+\t\t\t}\n+\t\t}\n+\n \t\t/* if verbose mode is enabled, dump debug info */\n \t\tif (verbose_level > 0) {\n \t\t\tstruct {\n@@ -648,6 +807,8 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)\n \t\t\tconst char *name;\n \n \t\t\tprintf(\"-----------------\\n\");\n+\t\t\tprintf(\"mbuf=%p, pkt_len=%u, nb_segs=%hhu:\\n\",\n+\t\t\t\tm, m->pkt_len, m->nb_segs);\n \t\t\t/* dump rx parsed packet info */\n \t\t\tprintf(\"rx: l2_len=%d ethertype=%x l3_len=%d \"\n \t\t\t\t\"l4_proto=%d l4_len=%d\\n\",\ndiff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c\nindex 2e302bb..25affe7 100644\n--- a/app/test-pmd/testpmd.c\n+++ b/app/test-pmd/testpmd.c\n@@ -173,6 +173,9 @@ uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT] = {\n };\n uint8_t  tx_pkt_nb_segs = 1; /**< Number of segments in TXONLY packets */\n \n+enum tx_pkt_split tx_pkt_split = TX_PKT_SPLIT_OFF;\n+/**< Split policy for packts to TX. */\n+\n uint16_t nb_pkt_per_burst = DEF_PKT_BURST; /**< Number of packets per burst. */\n uint16_t mb_mempool_cache = DEF_MBUF_CACHE; /**< Size of mbuf mempool cache. */\n \ndiff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h\nindex d6742d6..ee7de98 100644\n--- a/app/test-pmd/testpmd.h\n+++ b/app/test-pmd/testpmd.h\n@@ -361,6 +361,14 @@ extern uint16_t tx_pkt_length; /**< Length of TXONLY packet */\n extern uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT]; /**< Seg. lengths */\n extern uint8_t  tx_pkt_nb_segs; /**< Number of segments in TX packets */\n \n+enum tx_pkt_split {\n+\tTX_PKT_SPLIT_OFF,\n+\tTX_PKT_SPLIT_ON,\n+\tTX_PKT_SPLIT_RND,\n+};\n+\n+extern enum tx_pkt_split tx_pkt_split;\n+\n extern uint16_t nb_pkt_per_burst;\n extern uint16_t mb_mempool_cache;\n extern int8_t rx_pthresh;\n@@ -509,6 +517,8 @@ void set_qmap(portid_t port_id, uint8_t is_rx, uint16_t queue_id, uint8_t map_va\n \n void set_verbose_level(uint16_t vb_level);\n void set_tx_pkt_segments(unsigned *seg_lengths, unsigned nb_segs);\n+void show_tx_pkt_segments(void);\n+void set_tx_pkt_split(const char *name);\n void set_nb_pkt_per_burst(uint16_t pkt_burst);\n char *list_pkt_forwarding_modes(void);\n void set_pkt_forwarding_mode(const char *fwd_mode);\ndiff --git a/app/test-pmd/txonly.c b/app/test-pmd/txonly.c\nindex db8f37a..a903d4f 100644\n--- a/app/test-pmd/txonly.c\n+++ b/app/test-pmd/txonly.c\n@@ -210,6 +210,7 @@ pkt_burst_transmit(struct fwd_stream *fs)\n \tuint64_t end_tsc;\n \tuint64_t core_cycles;\n #endif\n+\tuint32_t nb_segs, pkt_len;\n \n #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES\n \tstart_tsc = rte_rdtsc();\n@@ -233,7 +234,12 @@ pkt_burst_transmit(struct fwd_stream *fs)\n \t\t}\n \t\tpkt->data_len = tx_pkt_seg_lengths[0];\n \t\tpkt_seg = pkt;\n-\t\tfor (i = 1; i < tx_pkt_nb_segs; i++) {\n+\t\tif (tx_pkt_split == TX_PKT_SPLIT_RND)\n+\t\t\tnb_segs = random() % tx_pkt_nb_segs + 1;\n+\t\telse\n+\t\t\tnb_segs = tx_pkt_nb_segs;\n+\t\tpkt_len = pkt->data_len;\n+\t\tfor (i = 1; i < nb_segs; i++) {\n \t\t\tpkt_seg->next = tx_mbuf_alloc(mbp);\n \t\t\tif (pkt_seg->next == NULL) {\n \t\t\t\tpkt->nb_segs = i;\n@@ -242,6 +248,7 @@ pkt_burst_transmit(struct fwd_stream *fs)\n \t\t\t}\n \t\t\tpkt_seg = pkt_seg->next;\n \t\t\tpkt_seg->data_len = tx_pkt_seg_lengths[i];\n+\t\t\tpkt_len += pkt_seg->data_len;\n \t\t}\n \t\tpkt_seg->next = NULL; /* Last segment of packet. */\n \n@@ -266,8 +273,8 @@ pkt_burst_transmit(struct fwd_stream *fs)\n \t\t * Complete first mbuf of packet and append it to the\n \t\t * burst of packets to be transmitted.\n \t\t */\n-\t\tpkt->nb_segs = tx_pkt_nb_segs;\n-\t\tpkt->pkt_len = tx_pkt_length;\n+\t\tpkt->nb_segs = nb_segs;\n+\t\tpkt->pkt_len = pkt_len;\n \t\tpkt->ol_flags = ol_flags;\n \t\tpkt->vlan_tci = vlan_tci;\n \t\tpkt->vlan_tci_outer = vlan_tci_outer;\ndiff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\nindex 4fb1e0b..4608b3f 100644\n--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n@@ -211,7 +211,7 @@ show config\n Displays the configuration of the application.\n The configuration comes from the command-line, the runtime or the application defaults::\n \n-   testpmd> show config (rxtx|cores|fwd)\n+   testpmd> show config (rxtx|cores|fwd|txpkts)\n \n The available information categories are:\n \n@@ -221,6 +221,8 @@ The available information categories are:\n \n * ``fwd``: Packet forwarding configuration.\n \n+* ``txpkts``: Packets to TX configuration.\n+\n For example:\n \n .. code-block:: console\n@@ -396,6 +398,13 @@ Set the length of each segment of the TX-ONLY packets::\n \n Where x[,y]* represents a CSV list of values, without white space.\n \n+set txsplit\n+~~~~~~~~~~~\n+\n+Set the length of each segment of the TX packets, applicable for TX-ONLY and CSUM forwarding modes::\n+\n+   testpmd> set txsplit (off|on|rand)\n+\n set corelist\n ~~~~~~~~~~~~\n \n",
    "prefixes": [
        "dpdk-dev",
        "PATCHv5",
        "1/2"
    ]
}