From patchwork Thu Nov 20 22:58:54 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Olivier Matz X-Patchwork-Id: 1406 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 224067FF5; Thu, 20 Nov 2014 23:48:55 +0100 (CET) Received: from mail-wg0-f44.google.com (mail-wg0-f44.google.com [74.125.82.44]) by dpdk.org (Postfix) with ESMTP id 681687F40 for ; Thu, 20 Nov 2014 23:48:45 +0100 (CET) Received: by mail-wg0-f44.google.com with SMTP id b13so5053136wgh.3 for ; Thu, 20 Nov 2014 14:59:17 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=q0thLtkuOtdUKlmLKbmH8iC6j2SoQq1X/tXdm9iK/cE=; b=LXzoYmY410tmH4+APvpe9uGVJm3Akj3ZSV+RhwTeFQaUgWEbqSTsAwaFkDZtLnXtZ8 PjKTAvf2DHt/lJ983jK/DTQHXJT5BL38pBb6kELinWqRyyfhZqbjhc8TcHDV4SQn9/Wy 6DzqNidsL7iVg2bxN/Y7lPIHdFwsOvqLCIguxlhg/UVmToVW9vicIgk7dMoIL15rAOLp Gb0kKf6p1dEaPz5kFZeCtFoPiI9pw38qqHDWrnSAT5ELkotgW2/u8Afb43DiV8xcC1d7 Ugj4ExkIrFy6WMbwd39KhBnxU1amtbDdDy9slgdcgnTbBo2Gdr5IWiXLKOn66B5iB8Sv XPMQ== X-Gm-Message-State: ALoCoQm4tsjW7oSKVakxrHnzQqDFjNriWOxXdrhkjW7keypAkskQm7w9K11pATMl2EesrhmT1K4F X-Received: by 10.194.237.162 with SMTP id vd2mr1501186wjc.52.1416524357296; Thu, 20 Nov 2014 14:59:17 -0800 (PST) Received: from glumotte.dev.6wind.com (guy78-3-82-239-227-177.fbx.proxad.net. [82.239.227.177]) by mx.google.com with ESMTPSA id cz3sm5380581wjb.23.2014.11.20.14.59.16 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 20 Nov 2014 14:59:16 -0800 (PST) From: Olivier Matz To: dev@dpdk.org Date: Thu, 20 Nov 2014 23:58:54 +0100 Message-Id: <1416524335-22753-13-git-send-email-olivier.matz@6wind.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1416524335-22753-1-git-send-email-olivier.matz@6wind.com> References: <1415984609-2484-1-git-send-email-olivier.matz@6wind.com> <1416524335-22753-1-git-send-email-olivier.matz@6wind.com> Cc: jigsaw@gmail.com Subject: [dpdk-dev] [PATCH v3 12/13] testpmd: support TSO in csum forward engine X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add two new commands in testpmd: - tso set - tso show These commands can be used enable TSO when transmitting TCP packets in the csum forward engine. Ex: set fwd csum tx_checksum set ip hw 0 tso set 800 0 start Signed-off-by: Olivier Matz --- app/test-pmd/cmdline.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ app/test-pmd/csumonly.c | 64 ++++++++++++++++++++++++---------- app/test-pmd/testpmd.h | 1 + 3 files changed, 139 insertions(+), 18 deletions(-) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index 61e4340..fe2ee41 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -323,6 +323,14 @@ static void cmd_help_long_parsed(void *parsed_result, "tx_checksum show (port_id)\n" " Display tx checksum offload configuration\n\n" + "tso set (segsize) (portid)\n" + " Enable TCP Segmentation Offload in csum forward" + " engine.\n" + " Please check the NIC datasheet for HW limits.\n\n" + + "tso show (portid)" + " Display the status of TCP Segmentation Offload.\n\n" + "set fwd (%s)\n" " Set packet forwarding mode.\n\n" @@ -2867,6 +2875,88 @@ cmdline_parse_inst_t cmd_tx_cksum_show = { }, }; +/* *** ENABLE HARDWARE SEGMENTATION IN TX PACKETS *** */ +struct cmd_tso_set_result { + cmdline_fixed_string_t tso; + cmdline_fixed_string_t mode; + uint16_t tso_segsz; + uint8_t port_id; +}; + +static void +cmd_tso_set_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_tso_set_result *res = parsed_result; + struct rte_eth_dev_info dev_info; + + if (port_id_is_invalid(res->port_id)) + return; + + if (!strcmp(res->mode, "set")) + ports[res->port_id].tso_segsz = res->tso_segsz; + + if (ports[res->port_id].tso_segsz == 0) + printf("TSO is disabled\n"); + else + printf("TSO segment size is %d\n", + ports[res->port_id].tso_segsz); + + /* display warnings if configuration is not supported by the NIC */ + rte_eth_dev_info_get(res->port_id, &dev_info); + if ((ports[res->port_id].tso_segsz != 0) && + (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_TCP_TSO) == 0) { + printf("Warning: TSO enabled but not " + "supported by port %d\n", res->port_id); + } +} + +cmdline_parse_token_string_t cmd_tso_set_tso = + TOKEN_STRING_INITIALIZER(struct cmd_tso_set_result, + tso, "tso"); +cmdline_parse_token_string_t cmd_tso_set_mode = + TOKEN_STRING_INITIALIZER(struct cmd_tso_set_result, + mode, "set"); +cmdline_parse_token_num_t cmd_tso_set_tso_segsz = + TOKEN_NUM_INITIALIZER(struct cmd_tso_set_result, + tso_segsz, UINT16); +cmdline_parse_token_num_t cmd_tso_set_portid = + TOKEN_NUM_INITIALIZER(struct cmd_tso_set_result, + port_id, UINT8); + +cmdline_parse_inst_t cmd_tso_set = { + .f = cmd_tso_set_parsed, + .data = NULL, + .help_str = "Set TSO segment size for csum engine (0 to disable): " + "tso set ", + .tokens = { + (void *)&cmd_tso_set_tso, + (void *)&cmd_tso_set_mode, + (void *)&cmd_tso_set_tso_segsz, + (void *)&cmd_tso_set_portid, + NULL, + }, +}; + +cmdline_parse_token_string_t cmd_tso_show_mode = + TOKEN_STRING_INITIALIZER(struct cmd_tso_set_result, + mode, "show"); + + +cmdline_parse_inst_t cmd_tso_show = { + .f = cmd_tso_set_parsed, + .data = NULL, + .help_str = "Show TSO segment size for csum engine: " + "tso show ", + .tokens = { + (void *)&cmd_tso_set_tso, + (void *)&cmd_tso_show_mode, + (void *)&cmd_tso_set_portid, + NULL, + }, +}; + /* *** ENABLE/DISABLE FLUSH ON RX STREAMS *** */ struct cmd_set_flush_rx { cmdline_fixed_string_t set; @@ -7880,6 +7970,8 @@ cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *)&cmd_tx_vlan_set_pvid, (cmdline_parse_inst_t *)&cmd_tx_cksum_set, (cmdline_parse_inst_t *)&cmd_tx_cksum_show, + (cmdline_parse_inst_t *)&cmd_tso_set, + (cmdline_parse_inst_t *)&cmd_tso_show, (cmdline_parse_inst_t *)&cmd_link_flow_control_set, (cmdline_parse_inst_t *)&cmd_link_flow_control_set_rx, (cmdline_parse_inst_t *)&cmd_link_flow_control_set_tx, diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c index 37d4129..ec9555f 100644 --- a/app/test-pmd/csumonly.c +++ b/app/test-pmd/csumonly.c @@ -88,12 +88,12 @@ #endif static uint16_t -get_psd_sum(void *l3_hdr, uint16_t ethertype) +get_psd_sum(void *l3_hdr, uint16_t ethertype, uint64_t ol_flags) { if (ethertype == _htons(ETHER_TYPE_IPv4)) - return rte_ipv4_phdr_cksum(l3_hdr); + return rte_ipv4_phdr_cksum(l3_hdr, ol_flags); else /* assume ethertype == ETHER_TYPE_IPv6 */ - return rte_ipv6_phdr_cksum(l3_hdr); + return rte_ipv6_phdr_cksum(l3_hdr, ol_flags); } static uint16_t @@ -108,14 +108,15 @@ get_udptcp_checksum(void *l3_hdr, void *l4_hdr, uint16_t ethertype) /* * Parse an ethernet header to fill the ethertype, l2_len, l3_len and * ipproto. This function is able to recognize IPv4/IPv6 with one optional vlan - * header. + * header. The l4_len argument is only set in case of TCP (useful for TSO). */ static void parse_ethernet(struct ether_hdr *eth_hdr, uint16_t *ethertype, uint16_t *l2_len, - uint16_t *l3_len, uint8_t *l4_proto) + uint16_t *l3_len, uint8_t *l4_proto, uint16_t *l4_len) { struct ipv4_hdr *ipv4_hdr; struct ipv6_hdr *ipv6_hdr; + struct tcp_hdr *tcp_hdr; *l2_len = sizeof(struct ether_hdr); *ethertype = eth_hdr->ether_type; @@ -143,6 +144,14 @@ parse_ethernet(struct ether_hdr *eth_hdr, uint16_t *ethertype, uint16_t *l2_len, *l4_proto = 0; break; } + + if (*l4_proto == IPPROTO_TCP) { + tcp_hdr = (struct tcp_hdr *)((char *)eth_hdr + + *l2_len + *l3_len); + *l4_len = (tcp_hdr->data_off & 0xf0) >> 2; + } + else + *l4_len = 0; } /* modify the IPv4 or IPv4 source address of a packet */ @@ -165,7 +174,7 @@ change_ip_addresses(void *l3_hdr, uint16_t ethertype) * depending on the testpmd command line configuration */ static uint64_t process_inner_cksums(void *l3_hdr, uint16_t ethertype, uint16_t l3_len, - uint8_t l4_proto, uint16_t testpmd_ol_flags) + uint8_t l4_proto, uint16_t tso_segsz, uint16_t testpmd_ol_flags) { struct ipv4_hdr *ipv4_hdr = l3_hdr; struct udp_hdr *udp_hdr; @@ -177,11 +186,16 @@ process_inner_cksums(void *l3_hdr, uint16_t ethertype, uint16_t l3_len, ipv4_hdr = l3_hdr; ipv4_hdr->hdr_checksum = 0; - if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_IP_CKSUM) + if (tso_segsz != 0 && l4_proto == IPPROTO_TCP) { ol_flags |= PKT_TX_IP_CKSUM; - else - ipv4_hdr->hdr_checksum = rte_ipv4_cksum(ipv4_hdr); - + } + else { + if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_IP_CKSUM) + ol_flags |= PKT_TX_IP_CKSUM; + else + ipv4_hdr->hdr_checksum = + rte_ipv4_cksum(ipv4_hdr); + } } else if (ethertype != _htons(ETHER_TYPE_IPv6)) return 0; /* packet type not supported nothing to do */ @@ -194,7 +208,7 @@ process_inner_cksums(void *l3_hdr, uint16_t ethertype, uint16_t l3_len, if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_UDP_CKSUM) { ol_flags |= PKT_TX_UDP_CKSUM; udp_hdr->dgram_cksum = get_psd_sum(l3_hdr, - ethertype); + ethertype, ol_flags); } else { udp_hdr->dgram_cksum = @@ -206,9 +220,13 @@ process_inner_cksums(void *l3_hdr, uint16_t ethertype, uint16_t l3_len, else if (l4_proto == IPPROTO_TCP) { tcp_hdr = (struct tcp_hdr *)((char *)l3_hdr + l3_len); tcp_hdr->cksum = 0; - if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_TCP_CKSUM) { + if (tso_segsz != 0) { + ol_flags |= PKT_TX_TCP_SEG; + tcp_hdr->cksum = get_psd_sum(l3_hdr, ethertype, ol_flags); + } + else if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_TCP_CKSUM) { ol_flags |= PKT_TX_TCP_CKSUM; - tcp_hdr->cksum = get_psd_sum(l3_hdr, ethertype); + tcp_hdr->cksum = get_psd_sum(l3_hdr, ethertype, ol_flags); } else { tcp_hdr->cksum = @@ -279,6 +297,8 @@ process_outer_cksums(void *outer_l3_hdr, uint16_t outer_ethertype, * - modify the IPs in inner headers and in outer headers if any * - reprocess the checksum of all supported layers. This is done in SW * or HW, depending on testpmd command line configuration + * - if TSO is enabled in testpmd command line, also flag the mbuf for TCP + * segmentation offload (this implies HW TCP checksum) * Then transmit packets on the output port. * * (1) Supported packets are: @@ -309,7 +329,9 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) uint16_t testpmd_ol_flags; uint8_t l4_proto; uint16_t ethertype = 0, outer_ethertype = 0; - uint16_t l2_len = 0, l3_len = 0, outer_l2_len = 0, outer_l3_len = 0; + uint16_t l2_len = 0, l3_len = 0, l4_len = 0; + uint16_t outer_l2_len = 0, outer_l3_len = 0; + uint16_t tso_segsz; int tunnel = 0; uint32_t rx_bad_ip_csum; uint32_t rx_bad_l4_csum; @@ -339,6 +361,7 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) txp = &ports[fs->tx_port]; testpmd_ol_flags = txp->tx_ol_flags; + tso_segsz = txp->tso_segsz; for (i = 0; i < nb_rx; i++) { @@ -354,7 +377,8 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) * and inner headers */ eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *); - parse_ethernet(eth_hdr, ðertype, &l2_len, &l3_len, &l4_proto); + parse_ethernet(eth_hdr, ðertype, &l2_len, &l3_len, + &l4_proto, &l4_len); l3_hdr = (char *)eth_hdr + l2_len; /* check if it's a supported tunnel (only vxlan for now) */ @@ -382,7 +406,7 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) sizeof(struct vxlan_hdr)); parse_ethernet(eth_hdr, ðertype, &l2_len, - &l3_len, &l4_proto); + &l3_len, &l4_proto, &l4_len); l3_hdr = (char *)eth_hdr + l2_len; } } @@ -396,11 +420,12 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) /* step 3: depending on user command line configuration, * recompute checksum either in software or flag the - * mbuf to offload the calculation to the NIC */ + * mbuf to offload the calculation to the NIC. If TSO + * is configured, prepare the mbuf for TCP segmentation. */ /* process checksums of inner headers first */ ol_flags |= process_inner_cksums(l3_hdr, ethertype, - l3_len, l4_proto, testpmd_ol_flags); + l3_len, l4_proto, tso_segsz, testpmd_ol_flags); /* Then process outer headers if any. Note that the software * checksum will be wrong if one of the inner checksums is @@ -429,6 +454,7 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) sizeof(struct udp_hdr) + sizeof(struct vxlan_hdr) + l2_len; m->l3_len = l3_len; + m->l4_len = l4_len; } } else { /* this is only useful if an offload flag is @@ -436,7 +462,9 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) * case */ m->l2_len = l2_len; m->l3_len = l3_len; + m->l4_len = l4_len; } + m->tso_segsz = tso_segsz; m->ol_flags = ol_flags; } diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index c753d37..c22863f 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -149,6 +149,7 @@ struct rte_port { struct fwd_stream *tx_stream; /**< Port TX stream, if unique */ unsigned int socket_id; /**< For NUMA support */ uint16_t tx_ol_flags;/**< TX Offload Flags (TESTPMD_TX_OFFLOAD...). */ + uint16_t tso_segsz; /**< MSS for segmentation offload. */ uint16_t tx_vlan_id; /**< Tag Id. in TX VLAN packets. */ void *fwd_ctx; /**< Forwarding mode context */ uint64_t rx_bad_ip_csum; /**< rx pkts with bad ip checksum */