get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 29676,
    "url": "https://patches.dpdk.org/api/patches/29676/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1507201331-228465-6-git-send-email-mark.b.kavanagh@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": "<1507201331-228465-6-git-send-email-mark.b.kavanagh@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1507201331-228465-6-git-send-email-mark.b.kavanagh@intel.com",
    "date": "2017-10-05T11:02:10",
    "name": "[dpdk-dev,v7,5/6] app/testpmd: enable TCP/IPv4, VxLAN and GRE GSO",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "5ee13a53ca564e2904f38d2922b27c24329c9a02",
    "submitter": {
        "id": 133,
        "url": "https://patches.dpdk.org/api/people/133/?format=api",
        "name": "Mark Kavanagh",
        "email": "mark.b.kavanagh@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1507201331-228465-6-git-send-email-mark.b.kavanagh@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/29676/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/29676/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 5A7161B1AB;\n\tThu,  5 Oct 2017 13:02:35 +0200 (CEST)",
            "from mga11.intel.com (mga11.intel.com [192.55.52.93])\n\tby dpdk.org (Postfix) with ESMTP id F37927D4E\n\tfor <dev@dpdk.org>; Thu,  5 Oct 2017 13:02:28 +0200 (CEST)",
            "from fmsmga005.fm.intel.com ([10.253.24.32])\n\tby fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t05 Oct 2017 04:02:28 -0700",
            "from silpixa00380299.ir.intel.com ([10.237.222.17])\n\tby fmsmga005.fm.intel.com with ESMTP; 05 Oct 2017 04:02:26 -0700"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.42,481,1500966000\"; d=\"scan'208\";a=\"159160367\"",
        "From": "Mark Kavanagh <mark.b.kavanagh@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "jiayu.hu@intel.com, jianfeng.tan@intel.com, konstantin.ananyev@intel.com,\n\tferruh.yigit@intel.com, thomas@monjalon.net,\n\tMark Kavanagh <mark.b.kavanagh@intel.com>",
        "Date": "Thu,  5 Oct 2017 12:02:10 +0100",
        "Message-Id": "<1507201331-228465-6-git-send-email-mark.b.kavanagh@intel.com>",
        "X-Mailer": "git-send-email 1.9.3",
        "In-Reply-To": "<1507201331-228465-1-git-send-email-mark.b.kavanagh@intel.com>",
        "References": "<1506962749-106779-1-git-send-email-mark.b.kavanagh@intel.com>\n\t<1507201331-228465-1-git-send-email-mark.b.kavanagh@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v7 5/6] app/testpmd: enable TCP/IPv4,\n\tVxLAN and GRE GSO",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <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": "From: Jiayu Hu <jiayu.hu@intel.com>\n\nThis patch adds GSO support to the csum forwarding engine. Oversized\npackets transmitted over a GSO-enabled port will undergo segmentation\n(with the exception of packet-types unsupported by the GSO library).\nGSO support is disabled by default.\n\nGSO support may be toggled on a per-port basis, using the command:\n\n        \"set port <port_id> gso on|off\"\n\nThe maximum packet length (including the packet header and payload) for\nGSO segments may be set with the command:\n\n        \"set gso segsz <length>\"\n\nShow GSO configuration for a given port with the command:\n\n\t\"show port <port_id> gso\"\n\nSigned-off-by: Jiayu Hu <jiayu.hu@intel.com>\nSigned-off-by: Mark Kavanagh <mark.b.kavanagh@intel.com>\n---\n app/test-pmd/cmdline.c                      | 179 ++++++++++++++++++++++++++++\n app/test-pmd/config.c                       |  24 ++++\n app/test-pmd/csumonly.c                     |  43 ++++++-\n app/test-pmd/testpmd.c                      |  13 ++\n app/test-pmd/testpmd.h                      |  10 ++\n doc/guides/testpmd_app_ug/testpmd_funcs.rst |  46 +++++++\n 6 files changed, 311 insertions(+), 4 deletions(-)",
    "diff": "diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c\nindex ccdf239..92e6171 100644\n--- a/app/test-pmd/cmdline.c\n+++ b/app/test-pmd/cmdline.c\n@@ -431,6 +431,17 @@ static void cmd_help_long_parsed(void *parsed_result,\n \t\t\t\"    Set max flow number and max packet number per-flow\"\n \t\t\t\" for GRO.\\n\\n\"\n \n+\t\t\t\"set port (port_id) gso (on|off)\"\n+\t\t\t\"    Enable or disable Generic Segmentation Offload in\"\n+\t\t\t\" csum forwarding engine.\\n\\n\"\n+\n+\t\t\t\"set gso segsz (length)\\n\"\n+\t\t\t\"    Set max packet length for output GSO segments,\"\n+\t\t\t\" including packet header and payload.\\n\\n\"\n+\n+\t\t\t\"show port (port_id) gso\\n\"\n+\t\t\t\"    Show GSO configuration.\\n\\n\"\n+\n \t\t\t\"set fwd (%s)\\n\"\n \t\t\t\"    Set packet forwarding mode.\\n\\n\"\n \n@@ -3967,6 +3978,171 @@ struct cmd_gro_set_result {\n \t},\n };\n \n+/* *** ENABLE/DISABLE GSO *** */\n+struct cmd_gso_enable_result {\n+\tcmdline_fixed_string_t cmd_set;\n+\tcmdline_fixed_string_t cmd_port;\n+\tcmdline_fixed_string_t cmd_keyword;\n+\tcmdline_fixed_string_t cmd_mode;\n+\tuint8_t cmd_pid;\n+};\n+\n+static void\n+cmd_gso_enable_parsed(void *parsed_result,\n+\t\t__attribute__((unused)) struct cmdline *cl,\n+\t\t__attribute__((unused)) void *data)\n+{\n+\tstruct cmd_gso_enable_result *res;\n+\n+\tres = parsed_result;\n+\tif (!strcmp(res->cmd_keyword, \"gso\"))\n+\t\tsetup_gso(res->cmd_mode, res->cmd_pid);\n+}\n+\n+cmdline_parse_token_string_t cmd_gso_enable_set =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_gso_enable_result,\n+\t\t\tcmd_set, \"set\");\n+cmdline_parse_token_string_t cmd_gso_enable_port =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_gso_enable_result,\n+\t\t\tcmd_port, \"port\");\n+cmdline_parse_token_string_t cmd_gso_enable_keyword =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_gso_enable_result,\n+\t\t\tcmd_keyword, \"gso\");\n+cmdline_parse_token_string_t cmd_gso_enable_mode =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_gso_enable_result,\n+\t\t\tcmd_mode, \"on#off\");\n+cmdline_parse_token_num_t cmd_gso_enable_pid =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_gso_enable_result,\n+\t\t\tcmd_pid, UINT8);\n+\n+cmdline_parse_inst_t cmd_gso_enable = {\n+\t.f = cmd_gso_enable_parsed,\n+\t.data = NULL,\n+\t.help_str = \"set port <port_id> gso on|off\",\n+\t.tokens = {\n+\t\t(void *)&cmd_gso_enable_set,\n+\t\t(void *)&cmd_gso_enable_port,\n+\t\t(void *)&cmd_gso_enable_pid,\n+\t\t(void *)&cmd_gso_enable_keyword,\n+\t\t(void *)&cmd_gso_enable_mode,\n+\t\tNULL,\n+\t},\n+};\n+\n+/* *** SET MAX PACKET LENGTH FOR GSO SEGMENTS *** */\n+struct cmd_gso_size_result {\n+\tcmdline_fixed_string_t cmd_set;\n+\tcmdline_fixed_string_t cmd_keyword;\n+\tcmdline_fixed_string_t cmd_segsz;\n+\tuint16_t cmd_size;\n+};\n+\n+static void\n+cmd_gso_size_parsed(void *parsed_result,\n+\t\t       __attribute__((unused)) struct cmdline *cl,\n+\t\t       __attribute__((unused)) void *data)\n+{\n+\tstruct cmd_gso_size_result *res = parsed_result;\n+\n+\tif (test_done == 0) {\n+\t\tprintf(\"Before setting GSO segsz, please first stop fowarding\\n\");\n+\t\treturn;\n+\t}\n+\n+\tif (!strcmp(res->cmd_keyword, \"gso\") &&\n+\t\t\t!strcmp(res->cmd_segsz, \"segsz\")) {\n+\t\tif (res->cmd_size < RTE_GSO_SEG_SIZE_MIN)\n+\t\t\tprintf(\"gso_size should be larger than %lu.\"\n+\t\t\t\t\t\" Please input a legal value\\n\",\n+\t\t\t\t\tRTE_GSO_SEG_SIZE_MIN);\n+\t\telse\n+\t\t\tgso_max_segment_size = res->cmd_size;\n+\t}\n+}\n+\n+cmdline_parse_token_string_t cmd_gso_size_set =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_gso_size_result,\n+\t\t\t\tcmd_set, \"set\");\n+cmdline_parse_token_string_t cmd_gso_size_keyword =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_gso_size_result,\n+\t\t\t\tcmd_keyword, \"gso\");\n+cmdline_parse_token_string_t cmd_gso_size_segsz =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_gso_size_result,\n+\t\t\t\tcmd_segsz, \"segsz\");\n+cmdline_parse_token_num_t cmd_gso_size_size =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_gso_size_result,\n+\t\t\t\tcmd_size, UINT16);\n+\n+cmdline_parse_inst_t cmd_gso_size = {\n+\t.f = cmd_gso_size_parsed,\n+\t.data = NULL,\n+\t.help_str = \"set gso segsz <length>\",\n+\t.tokens = {\n+\t\t(void *)&cmd_gso_size_set,\n+\t\t(void *)&cmd_gso_size_keyword,\n+\t\t(void *)&cmd_gso_size_segsz,\n+\t\t(void *)&cmd_gso_size_size,\n+\t\tNULL,\n+\t},\n+};\n+\n+/* *** SHOW GSO CONFIGURATION *** */\n+struct cmd_gso_show_result {\n+\tcmdline_fixed_string_t cmd_show;\n+\tcmdline_fixed_string_t cmd_port;\n+\tcmdline_fixed_string_t cmd_keyword;\n+\tuint8_t cmd_pid;\n+};\n+\n+static void\n+cmd_gso_show_parsed(void *parsed_result,\n+\t\t       __attribute__((unused)) struct cmdline *cl,\n+\t\t       __attribute__((unused)) void *data)\n+{\n+\tstruct cmd_gso_show_result *res = parsed_result;\n+\n+\tif (!rte_eth_dev_is_valid_port(res->cmd_pid)) {\n+\t\tprintf(\"invalid port id %u\\n\", res->cmd_pid);\n+\t\treturn;\n+\t}\n+\tif (!strcmp(res->cmd_keyword, \"gso\")) {\n+\t\tif (gso_ports[res->cmd_pid].enable) {\n+\t\t\tprintf(\"Max GSO'd packet size: %uB\\n\"\n+\t\t\t\t\t\"Supported GSO types: TCP/IPv4, \"\n+\t\t\t\t\t\"VxLAN with inner TCP/IPv4 packet, \"\n+\t\t\t\t\t\"GRE with inner TCP/IPv4  packet\\n\",\n+\t\t\t\t\tgso_max_segment_size);\n+\t\t} else\n+\t\t\tprintf(\"GSO is not enabled on Port %u\\n\", res->cmd_pid);\n+\t}\n+}\n+\n+cmdline_parse_token_string_t cmd_gso_show_show =\n+TOKEN_STRING_INITIALIZER(struct cmd_gso_show_result,\n+\t\tcmd_show, \"show\");\n+cmdline_parse_token_string_t cmd_gso_show_port =\n+TOKEN_STRING_INITIALIZER(struct cmd_gso_show_result,\n+\t\tcmd_port, \"port\");\n+cmdline_parse_token_string_t cmd_gso_show_keyword =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_gso_show_result,\n+\t\t\t\tcmd_keyword, \"gso\");\n+cmdline_parse_token_num_t cmd_gso_show_pid =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_gso_show_result,\n+\t\t\t\tcmd_pid, UINT8);\n+\n+cmdline_parse_inst_t cmd_gso_show = {\n+\t.f = cmd_gso_show_parsed,\n+\t.data = NULL,\n+\t.help_str = \"show port <port_id> gso\",\n+\t.tokens = {\n+\t\t(void *)&cmd_gso_show_show,\n+\t\t(void *)&cmd_gso_show_port,\n+\t\t(void *)&cmd_gso_show_pid,\n+\t\t(void *)&cmd_gso_show_keyword,\n+\t\tNULL,\n+\t},\n+};\n+\n /* *** ENABLE/DISABLE FLUSH ON RX STREAMS *** */\n struct cmd_set_flush_rx {\n \tcmdline_fixed_string_t set;\n@@ -14255,6 +14431,9 @@ struct cmd_cmdfile_result {\n \t(cmdline_parse_inst_t *)&cmd_tunnel_tso_show,\n \t(cmdline_parse_inst_t *)&cmd_enable_gro,\n \t(cmdline_parse_inst_t *)&cmd_gro_set,\n+\t(cmdline_parse_inst_t *)&cmd_gso_enable,\n+\t(cmdline_parse_inst_t *)&cmd_gso_size,\n+\t(cmdline_parse_inst_t *)&cmd_gso_show,\n \t(cmdline_parse_inst_t *)&cmd_link_flow_control_set,\n \t(cmdline_parse_inst_t *)&cmd_link_flow_control_set_rx,\n \t(cmdline_parse_inst_t *)&cmd_link_flow_control_set_tx,\ndiff --git a/app/test-pmd/config.c b/app/test-pmd/config.c\nindex 3ae3e1c..88d09d0 100644\n--- a/app/test-pmd/config.c\n+++ b/app/test-pmd/config.c\n@@ -2454,6 +2454,30 @@ struct igb_ring_desc_16_bytes {\n \t}\n }\n \n+void\n+setup_gso(const char *mode, uint8_t port_id)\n+{\n+\tif (!rte_eth_dev_is_valid_port(port_id)) {\n+\t\tprintf(\"invalid port id %u\\n\", port_id);\n+\t\treturn;\n+\t}\n+\tif (strcmp(mode, \"on\") == 0) {\n+\t\tif (test_done == 0) {\n+\t\t\tprintf(\"before enabling GSO,\"\n+\t\t\t\t\t\" please stop forwarding first\\n\");\n+\t\t\treturn;\n+\t\t}\n+\t\tgso_ports[port_id].enable = 1;\n+\t} else if (strcmp(mode, \"off\") == 0) {\n+\t\tif (test_done == 0) {\n+\t\t\tprintf(\"before disabling GSO,\"\n+\t\t\t\t\t\" please stop forwarding first\\n\");\n+\t\t\treturn;\n+\t\t}\n+\t\tgso_ports[port_id].enable = 0;\n+\t}\n+}\n+\n char*\n list_pkt_forwarding_modes(void)\n {\ndiff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c\nindex 90c8119..81a631c 100644\n--- a/app/test-pmd/csumonly.c\n+++ b/app/test-pmd/csumonly.c\n@@ -70,6 +70,8 @@\n #include <rte_string_fns.h>\n #include <rte_flow.h>\n #include <rte_gro.h>\n+#include <rte_gso.h>\n+\n #include \"testpmd.h\"\n \n #define IP_DEFTTL  64   /* from RFC 1340. */\n@@ -91,6 +93,7 @@\n /* structure that caches offload info for the current packet */\n struct testpmd_offload_info {\n \tuint16_t ethertype;\n+\tuint8_t gso_enable;\n \tuint16_t l2_len;\n \tuint16_t l3_len;\n \tuint16_t l4_len;\n@@ -381,6 +384,8 @@ struct simple_gre_hdr {\n \t\t\t\tget_udptcp_checksum(l3_hdr, tcp_hdr,\n \t\t\t\t\tinfo->ethertype);\n \t\t}\n+\t\tif (info->gso_enable)\n+\t\t\tol_flags |= PKT_TX_TCP_SEG;\n \t} else if (info->l4_proto == IPPROTO_SCTP) {\n \t\tsctp_hdr = (struct sctp_hdr *)((char *)l3_hdr + info->l3_len);\n \t\tsctp_hdr->cksum = 0;\n@@ -627,6 +632,9 @@ struct simple_gre_hdr {\n pkt_burst_checksum_forward(struct fwd_stream *fs)\n {\n \tstruct rte_mbuf *pkts_burst[MAX_PKT_BURST];\n+\tstruct rte_mbuf *gso_segments[GSO_MAX_PKT_BURST];\n+\tstruct rte_gso_ctx *gso_ctx;\n+\tstruct rte_mbuf **tx_pkts_burst;\n \tstruct rte_port *txp;\n \tstruct rte_mbuf *m, *p;\n \tstruct ether_hdr *eth_hdr;\n@@ -641,6 +649,8 @@ struct simple_gre_hdr {\n \tuint32_t rx_bad_ip_csum;\n \tuint32_t rx_bad_l4_csum;\n \tstruct testpmd_offload_info info;\n+\tuint16_t nb_segments = 0;\n+\tint ret;\n \n #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES\n \tuint64_t start_tsc;\n@@ -674,6 +684,8 @@ struct simple_gre_hdr {\n \tmemset(&info, 0, sizeof(info));\n \tinfo.tso_segsz = txp->tso_segsz;\n \tinfo.tunnel_tso_segsz = txp->tunnel_tso_segsz;\n+\tif (gso_ports[fs->tx_port].enable)\n+\t\tinfo.gso_enable = 1;\n \n \tfor (i = 0; i < nb_rx; i++) {\n \t\tif (likely(i < nb_rx - 1))\n@@ -851,13 +863,35 @@ struct simple_gre_hdr {\n \t\t}\n \t}\n \n+\tif (gso_ports[fs->tx_port].enable == 0)\n+\t\ttx_pkts_burst = pkts_burst;\n+\telse {\n+\t\tgso_ctx = &(current_fwd_lcore()->gso_ctx);\n+\t\tgso_ctx->gso_size = gso_max_segment_size;\n+\t\tfor (i = 0; i < nb_rx; i++) {\n+\t\t\tret = rte_gso_segment(pkts_burst[i], gso_ctx,\n+\t\t\t\t\t&gso_segments[nb_segments],\n+\t\t\t\t\tRTE_DIM(gso_segments) - nb_segments);\n+\t\t\tif (ret < 0)  {\n+\t\t\t\tRTE_LOG(DEBUG, USER1,\n+\t\t\t\t\t\t\"Unable to segment \\\n+\t\t\t\t\t\tpacket %d of %d\", i, nb_rx);\n+\t\t\t\trte_pktmbuf_free(pkts_burst[i]);\n+\t\t\t} else\n+\t\t\t\tnb_segments += ret;\n+\t\t}\n+\n+\t\ttx_pkts_burst = gso_segments;\n+\t\tnb_rx = nb_segments;\n+\t}\n+\n \tnb_prep = rte_eth_tx_prepare(fs->tx_port, fs->tx_queue,\n-\t\t\tpkts_burst, nb_rx);\n+\t\t\ttx_pkts_burst, nb_rx);\n \tif (nb_prep != nb_rx)\n \t\tprintf(\"Preparing packet burst to transmit failed: %s\\n\",\n \t\t\t\trte_strerror(rte_errno));\n \n-\tnb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst,\n+\tnb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, tx_pkts_burst,\n \t\t\tnb_prep);\n \n \t/*\n@@ -868,7 +902,7 @@ struct simple_gre_hdr {\n \t\twhile (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {\n \t\t\trte_delay_us(burst_tx_delay_time);\n \t\t\tnb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,\n-\t\t\t\t\t&pkts_burst[nb_tx], nb_rx - nb_tx);\n+\t\t\t\t\t&tx_pkts_burst[nb_tx], nb_rx - nb_tx);\n \t\t}\n \t}\n \tfs->tx_packets += nb_tx;\n@@ -881,9 +915,10 @@ struct simple_gre_hdr {\n \tif (unlikely(nb_tx < nb_rx)) {\n \t\tfs->fwd_dropped += (nb_rx - nb_tx);\n \t\tdo {\n-\t\t\trte_pktmbuf_free(pkts_burst[nb_tx]);\n+\t\t\trte_pktmbuf_free(tx_pkts_burst[nb_tx]);\n \t\t} while (++nb_tx < nb_rx);\n \t}\n+\n #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES\n \tend_tsc = rte_rdtsc();\n \tcore_cycles = (end_tsc - start_tsc);\ndiff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c\nindex e097ee0..b9ee77c 100644\n--- a/app/test-pmd/testpmd.c\n+++ b/app/test-pmd/testpmd.c\n@@ -400,6 +400,9 @@ static int eth_event_callback(uint8_t port_id,\n  */\n static int all_ports_started(void);\n \n+struct gso_status gso_ports[RTE_MAX_ETHPORTS];\n+uint16_t gso_max_segment_size = ETHER_MAX_LEN - ETHER_CRC_LEN;\n+\n /*\n  * Helper function to check if socket is already discovered.\n  * If yes, return positive value. If not, return zero.\n@@ -570,6 +573,7 @@ static int eth_event_callback(uint8_t port_id,\n \tunsigned int nb_mbuf_per_pool;\n \tlcoreid_t  lc_id;\n \tuint8_t port_per_socket[RTE_MAX_NUMA_NODES];\n+\tuint32_t gso_types = 0;\n \n \tmemset(port_per_socket,0,RTE_MAX_NUMA_NODES);\n \n@@ -654,6 +658,8 @@ static int eth_event_callback(uint8_t port_id,\n \n \tinit_port_config();\n \n+\tgso_types = DEV_TX_OFFLOAD_TCP_TSO | DEV_TX_OFFLOAD_VXLAN_TNL_TSO |\n+\t\tDEV_TX_OFFLOAD_GRE_TNL_TSO;\n \t/*\n \t * Records which Mbuf pool to use by each logical core, if needed.\n \t */\n@@ -664,6 +670,13 @@ static int eth_event_callback(uint8_t port_id,\n \t\tif (mbp == NULL)\n \t\t\tmbp = mbuf_pool_find(0);\n \t\tfwd_lcores[lc_id]->mbp = mbp;\n+\t\t/* initialize GSO context */\n+\t\tfwd_lcores[lc_id]->gso_ctx.direct_pool = mbp;\n+\t\tfwd_lcores[lc_id]->gso_ctx.indirect_pool = mbp;\n+\t\tfwd_lcores[lc_id]->gso_ctx.gso_types = gso_types;\n+\t\tfwd_lcores[lc_id]->gso_ctx.gso_size = ETHER_MAX_LEN -\n+\t\t\tETHER_CRC_LEN;\n+\t\tfwd_lcores[lc_id]->gso_ctx.flag = 0;\n \t}\n \n \t/* Configuration of packet forwarding streams. */\ndiff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h\nindex 1d1ee75..ff842a1 100644\n--- a/app/test-pmd/testpmd.h\n+++ b/app/test-pmd/testpmd.h\n@@ -36,6 +36,7 @@\n \n #include <rte_pci.h>\n #include <rte_gro.h>\n+#include <rte_gso.h>\n \n #define RTE_PORT_ALL            (~(portid_t)0x0)\n \n@@ -205,6 +206,7 @@ struct rte_port {\n  * CPU id. configuration table.\n  */\n struct fwd_lcore {\n+\tstruct rte_gso_ctx gso_ctx;     /**< GSO context */\n \tstruct rte_mempool *mbp; /**< The mbuf pool to use by this core */\n \tstreamid_t stream_idx;   /**< index of 1st stream in \"fwd_streams\" */\n \tstreamid_t stream_nb;    /**< number of streams in \"fwd_streams\" */\n@@ -442,6 +444,13 @@ struct gro_status {\n };\n extern struct gro_status gro_ports[RTE_MAX_ETHPORTS];\n \n+#define GSO_MAX_PKT_BURST 2048\n+struct gso_status {\n+\tuint8_t enable;\n+};\n+extern struct gso_status gso_ports[RTE_MAX_ETHPORTS];\n+extern uint16_t gso_max_segment_size;\n+\n static inline unsigned int\n lcore_num(void)\n {\n@@ -642,6 +651,7 @@ void port_rss_hash_key_update(portid_t port_id, char rss_type[],\n int rx_queue_id_is_invalid(queueid_t rxq_id);\n int tx_queue_id_is_invalid(queueid_t txq_id);\n void setup_gro(const char *mode, uint8_t port_id);\n+void setup_gso(const char *mode, uint8_t port_id);\n \n /* Functions to manage the set of filtered Multicast MAC addresses */\n void mcast_addr_add(uint8_t port_id, struct ether_addr *mc_addr);\ndiff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\nindex 2ed62f5..f9b5bda 100644\n--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst\n@@ -932,6 +932,52 @@ number of packets a GRO table can store.\n If current packet number is greater than or equal to the max value, GRO\n will stop processing incoming packets.\n \n+set port - gso\n+~~~~~~~~~~~~~~\n+\n+Toggle per-port GSO support in ``csum`` forwarding engine::\n+\n+   testpmd> set port <port_id> gso on|off\n+\n+If enabled, the csum forwarding engine will perform GSO on supported IPv4\n+packets, transmitted on the given port.\n+\n+If disabled, packets transmitted on the given port will not undergo GSO.\n+By default, GSO is disabled for all ports.\n+\n+.. note::\n+\n+   When GSO is enabled on a port, supported IPv4 packets transmitted on that\n+   port undergo GSO. Afterwards, the segmented packets are represented by\n+   multi-segment mbufs; however, the csum forwarding engine doesn't calculation\n+   of checksums for GSO'd segments in SW. As a result, if users want correct\n+   checksums in GSO segments, they should enable HW checksum calculation for\n+   GSO-enabled ports.\n+\n+   For example, HW checksum calculation for VxLAN GSO'd packets may be enabled\n+   by setting the following options in the csum forwarding engine:\n+\n+   testpmd> csum set outer_ip hw <port_id>\n+\n+   testpmd> csum set ip hw <port_id>\n+\n+   testpmd> csum set tcp hw <port_id>\n+\n+set gso segsz\n+~~~~~~~~~~~~~\n+\n+Set the maximum GSO segment size (measured in bytes), which includes the\n+packet header and the packet payload for GSO-enabled ports (global)::\n+\n+   testpmd> set gso segsz <length>\n+\n+show port - gso\n+~~~~~~~~~~~~~~~\n+\n+Display the status of Generic Segmentation Offload for a given port::\n+\n+   testpmd> show port <port_id> gso\n+\n mac_addr add\n ~~~~~~~~~~~~\n \n",
    "prefixes": [
        "dpdk-dev",
        "v7",
        "5/6"
    ]
}