From patchwork Wed Nov 26 15:04: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: 1646 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 B284F7FDC; Wed, 26 Nov 2014 15:55:34 +0100 (CET) Received: from mail-wi0-f176.google.com (mail-wi0-f176.google.com [209.85.212.176]) by dpdk.org (Postfix) with ESMTP id 2237D7F7D for ; Wed, 26 Nov 2014 15:54:30 +0100 (CET) Received: by mail-wi0-f176.google.com with SMTP id ex7so12812695wid.9 for ; Wed, 26 Nov 2014 07:05:27 -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=VNenjErAkK3SAePOXSVHg0TVGVVINRWpPHCnq4TQutM=; b=izSAf+/Ved37XDKliN0lN6RHnY2dvEZ51ntlQBuiYjRCDcqXXbvk88rsMl7WiPBnj0 RS9oWavrygMMPbFGfAqCZWbscwIerSXs1dod1IBny9VmHyO0YX3G9eieiME1RSmyKipH qheSnIUXVRsPIAg+rgt0oTJb5DSUS+0Z0lZx7CJPkDLqv5+p+rh8yaPDp+MUicNPyops Mgr3NpY+7ICNDyKCCR8MrWpb9rsLA3HRibrV5Clh+D/OTUoZMZR8nVMGll3jKMjHF0He 8kiXc10ONA1CQuQWw4PUcmu35IE1kvStunhisiuCeHlu5X2IDlq0Ok7blisIdJqWvGkn sVTg== X-Gm-Message-State: ALoCoQmQKIVlsRflum00Et83rBV3Pq5Ydvgbd6/XHPoOOELxmbLKHLOqRhpyCC6R7LPREAeStxP0 X-Received: by 10.194.23.10 with SMTP id i10mr48665543wjf.11.1417014327279; Wed, 26 Nov 2014 07:05:27 -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 bm1sm6682819wjb.45.2014.11.26.07.05.25 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 26 Nov 2014 07:05:26 -0800 (PST) From: Olivier Matz To: dev@dpdk.org Date: Wed, 26 Nov 2014 16:04:54 +0100 Message-Id: <1417014295-29064-13-git-send-email-olivier.matz@6wind.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1417014295-29064-1-git-send-email-olivier.matz@6wind.com> References: <1416524335-22753-1-git-send-email-olivier.matz@6wind.com> <1417014295-29064-1-git-send-email-olivier.matz@6wind.com> Cc: jigsaw@gmail.com Subject: [dpdk-dev] [PATCH v4 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 Acked-by: Konstantin Ananyev --- 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 722cd76..2a8c260 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -329,6 +329,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" @@ -2984,6 +2992,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; @@ -8660,6 +8750,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 9a5408e..490342f 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); + } ol_flags |= PKT_TX_IPV4; } else if (ethertype == _htons(ETHER_TYPE_IPv6)) @@ -197,7 +211,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 = @@ -209,9 +223,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 = @@ -282,6 +300,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: @@ -312,7 +332,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; @@ -342,6 +364,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++) { @@ -357,7 +380,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) */ @@ -385,7 +409,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; } } @@ -399,11 +423,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 @@ -432,6 +457,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 @@ -439,7 +465,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 83311fa..16c6fbf 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 */