From patchwork Fri Nov 14 17:03:28 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Olivier Matz X-Patchwork-Id: 1282 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 DAD188006; Fri, 14 Nov 2014 17:54:22 +0100 (CET) Received: from mail-wg0-f41.google.com (mail-wg0-f41.google.com [74.125.82.41]) by dpdk.org (Postfix) with ESMTP id 334267F9C for ; Fri, 14 Nov 2014 17:54:01 +0100 (CET) Received: by mail-wg0-f41.google.com with SMTP id y19so643707wgg.28 for ; Fri, 14 Nov 2014 09:04:05 -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=oniyS6gU+T9/qHYGHtgCYfy+XZ6pECMV2NBaaOx67s8=; b=k+e2SOLrKg7EoFyIZ+OYhGyKC36v8yPA0TJflWoBQoMf3WgeRcrt2kTI+brof90NYF jcrHRNt+g3FaCt0GtN4fVWZcjzLdL9Y7hqx84ecAlgY6566lvTBn1CVcRF63Ty4Qx5aW p71EyteDf9O7E+xiaRAaqc1XAlBD2GiNdw2iCZLowjZemd52OG4Q6Bnf4DQeEEG6hQvK y2RsJNtPRPW5bJb7gLoXHYWoUFA5AWWFT+dJZfM9ztEzU0ZN04lKP4CRvGgeXHVWYaXP LaC+LklFh+TbT8b6L0Tg0JrvazWikKVyTsMFUu/4EAR0+dfMv3hhTqNAqvNugsGR4ALS pgog== X-Gm-Message-State: ALoCoQlbXerPNzD5znjwPGtlBXGCiODwtpRk1J1LPFWsOe9ZWG1GyHkQiorpYp5ciN54DW9kvb9P X-Received: by 10.194.250.41 with SMTP id yz9mr16243611wjc.34.1415984645169; Fri, 14 Nov 2014 09:04:05 -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 cu9sm40352554wjb.0.2014.11.14.09.04.03 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 14 Nov 2014 09:04:04 -0800 (PST) From: Olivier Matz To: dev@dpdk.org Date: Fri, 14 Nov 2014 18:03:28 +0100 Message-Id: <1415984609-2484-13-git-send-email-olivier.matz@6wind.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1415984609-2484-1-git-send-email-olivier.matz@6wind.com> References: <1415635166-1364-1-git-send-email-olivier.matz@6wind.com> <1415984609-2484-1-git-send-email-olivier.matz@6wind.com> Cc: jigsaw@gmail.com Subject: [dpdk-dev] [PATCH v2 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 0361e58..5460415 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -318,6 +318,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" @@ -2862,6 +2870,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; @@ -7875,6 +7965,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 39f974d..9a2beac 100644 --- a/app/test-pmd/csumonly.c +++ b/app/test-pmd/csumonly.c @@ -87,12 +87,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 @@ -107,14 +107,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; @@ -142,6 +143,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 */ @@ -164,7 +173,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; @@ -176,11 +185,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 */ @@ -193,7 +207,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 = @@ -205,9 +219,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 = @@ -276,6 +294,8 @@ process_outer_cksums(void *outer_l3_hdr, uint16_t outer_ethertype, * - modify the IPs * - reprocess the checksum 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 checksum) * Then packets are transmitted on the output port. * * Supported packets are: @@ -301,7 +321,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; @@ -331,6 +353,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++) { @@ -346,7 +369,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) */ @@ -374,7 +398,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; } } @@ -388,11 +412,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 @@ -421,6 +446,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 @@ -428,7 +454,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 */