From patchwork Tue Jan 10 22:02:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Gardner X-Patchwork-Id: 713448 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) by ozlabs.org (Postfix) with ESMTP id 3tymGq00YTz9t6g; Wed, 11 Jan 2017 09:02:43 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=canonical-com.20150623.gappssmtp.com header.i=@canonical-com.20150623.gappssmtp.com header.b="G5KiZ7XW"; dkim-atps=neutral Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1cR4V5-0007pN-H5; Tue, 10 Jan 2017 22:02:39 +0000 Received: from mail-io0-f176.google.com ([209.85.223.176]) by huckleberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1cR4Ux-0007oE-GG for kernel-team@lists.ubuntu.com; Tue, 10 Jan 2017 22:02:31 +0000 Received: by mail-io0-f176.google.com with SMTP id j18so69458267ioe.2 for ; Tue, 10 Jan 2017 14:02:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical-com.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:in-reply-to:references; bh=KlNxyfhkBXML5xD30o9P1FQRpQSSDGPeqI19PKwAmjk=; b=G5KiZ7XWcJxKfeOPMwH7fQ2+i8KtcrO0dXW45JJPqTD9ZdsJfhtYG3Sn7V7tgf3rD1 hr67uwllTO8HFKCdjmA3ZUVC+pkaqg4jz1s8OXiE1yKWJth+GMgCij+Va8Xrk1CbszaD A4fuvBFwTkpHnLF98AvuRuHZHG50fee3DMikK1KmdT7oAgoRfDzqie3Iams9jcoW+JI5 KFbvBT1Jkg36TuCE4JtKQNMwwBC3TwOhM7cSJ8+9kZxDpFuYhkOJeLjlve4sdamUtIOl kExJctqqIytTvQ0Bqh6YQR7fE/TTUPLcnu9Hy+Jrl+jTRfk8yGktdgS/fIM5vnEF2JMC hRGQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=KlNxyfhkBXML5xD30o9P1FQRpQSSDGPeqI19PKwAmjk=; b=rC/fK9urKM7To/5q+l6d4hp0bJA37mPO8aoKHVq/Y6YNsx0qkqP+GnO7GXvVUDdrFw 1SShfityt5ij8HULkR9yZUMV5yeRZSVqvg/kImt6cAxTelkrlBCAYoAnhg+asmXOeKib gbDwxtf8VVrJOi1bhoRaRuzcMP8jWzBQEMfeXIb5AOQTnTJzLm4D/9TYF7mXn+Tau+N2 kvGoh5+Xff09j0QR6n+rbUnaekHO9GfacvE0LlyXaNXYKupStczv3ld5Y08/0hGnyFNW kyGVL49OFH/EAIKsaKwEpzKonlxjT8tbr1G1+TLyeY/vgY7DGy34+DwW+4U0kM/3IXe1 0cTQ== X-Gm-Message-State: AIkVDXJceWnbR6y6bM604/GpN6aB5VteMnDEzW32tUzZij50KZAwHboLZ15AoavIzM4orBp4 X-Received: by 10.107.3.10 with SMTP id 10mr4998733iod.231.1484085750248; Tue, 10 Jan 2017 14:02:30 -0800 (PST) Received: from localhost.localdomain (host-98-127-250-84.bln-mt.client.bresnan.net. [98.127.250.84]) by smtp.gmail.com with ESMTPSA id l3sm1963533iof.33.2017.01.10.14.02.29 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 10 Jan 2017 14:02:29 -0800 (PST) From: Tim Gardner To: kernel-team@lists.ubuntu.com Subject: [PATCH 1/2] ibmveth: set correct gso_size and gso_type Date: Tue, 10 Jan 2017 15:02:23 -0700 Message-Id: <1484085744-9942-2-git-send-email-tim.gardner@canonical.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1484085744-9942-1-git-send-email-tim.gardner@canonical.com> References: <1484085744-9942-1-git-send-email-tim.gardner@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: kernel-team-bounces@lists.ubuntu.com From: Thomas Falcon BugLink: http://bugs.launchpad.net/bugs/1655420 This patch is based on an earlier one submitted by Jon Maxwell with the following commit message: "We recently encountered a bug where a few customers using ibmveth on the same LPAR hit an issue where a TCP session hung when large receive was enabled. Closer analysis revealed that the session was stuck because the one side was advertising a zero window repeatedly. We narrowed this down to the fact the ibmveth driver did not set gso_size which is translated by TCP into the MSS later up the stack. The MSS is used to calculate the TCP window size and as that was abnormally large, it was calculating a zero window, even although the sockets receive buffer was completely empty." We rely on the Virtual I/O Server partition in a pseries environment to provide the MSS through the TCP header checksum field. The stipulation is that users should not disable checksum offloading if rx packet aggregation is enabled through VIOS. Some firmware offerings provide the MSS in the RX buffer. This is signalled by a bit in the RX queue descriptor. Reviewed-by: Brian King Reviewed-by: Pradeep Satyanarayana Reviewed-by: Marcelo Ricardo Leitner Reviewed-by: Jonathan Maxwell Reviewed-by: David Dai Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller (cherry picked from commit 7b5967389f5a8dfb9d32843830f5e2717e20995d) Signed-off-by: Tim Gardner --- drivers/net/ethernet/ibm/ibmveth.c | 65 ++++++++++++++++++++++++++++++++++++-- drivers/net/ethernet/ibm/ibmveth.h | 1 + 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 7af870a..855c43d 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -58,7 +58,7 @@ static struct kobj_type ktype_veth_pool; static const char ibmveth_driver_name[] = "ibmveth"; static const char ibmveth_driver_string[] = "IBM Power Virtual Ethernet Driver"; -#define ibmveth_driver_version "1.05" +#define ibmveth_driver_version "1.06" MODULE_AUTHOR("Santiago Leon "); MODULE_DESCRIPTION("IBM Power Virtual Ethernet Driver"); @@ -137,6 +137,11 @@ static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter) return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK; } +static inline int ibmveth_rxq_large_packet(struct ibmveth_adapter *adapter) +{ + return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_LRG_PKT; +} + static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter) { return be32_to_cpu(adapter->rx_queue.queue_addr[adapter->rx_queue.index].length); @@ -1172,6 +1177,45 @@ map_failed: goto retry_bounce; } +static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt) +{ + int offset = 0; + + /* only TCP packets will be aggregated */ + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *iph = (struct iphdr *)skb->data; + + if (iph->protocol == IPPROTO_TCP) { + offset = iph->ihl * 4; + skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; + } else { + return; + } + } else if (skb->protocol == htons(ETH_P_IPV6)) { + struct ipv6hdr *iph6 = (struct ipv6hdr *)skb->data; + + if (iph6->nexthdr == IPPROTO_TCP) { + offset = sizeof(struct ipv6hdr); + skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; + } else { + return; + } + } else { + return; + } + /* if mss is not set through Large Packet bit/mss in rx buffer, + * expect that the mss will be written to the tcp header checksum. + */ + if (lrg_pkt) { + skb_shinfo(skb)->gso_size = mss; + } else if (offset) { + struct tcphdr *tcph = (struct tcphdr *)(skb->data + offset); + + skb_shinfo(skb)->gso_size = ntohs(tcph->check); + tcph->check = 0; + } +} + static int ibmveth_poll(struct napi_struct *napi, int budget) { struct ibmveth_adapter *adapter = @@ -1180,6 +1224,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) int frames_processed = 0; unsigned long lpar_rc; struct iphdr *iph; + u16 mss = 0; restart_poll: while (frames_processed < budget) { @@ -1197,9 +1242,21 @@ restart_poll: int length = ibmveth_rxq_frame_length(adapter); int offset = ibmveth_rxq_frame_offset(adapter); int csum_good = ibmveth_rxq_csum_good(adapter); + int lrg_pkt = ibmveth_rxq_large_packet(adapter); skb = ibmveth_rxq_get_buffer(adapter); + /* if the large packet bit is set in the rx queue + * descriptor, the mss will be written by PHYP eight + * bytes from the start of the rx buffer, which is + * skb->data at this stage + */ + if (lrg_pkt) { + __be64 *rxmss = (__be64 *)(skb->data + 8); + + mss = (u16)be64_to_cpu(*rxmss); + } + new_skb = NULL; if (length < rx_copybreak) new_skb = netdev_alloc_skb(netdev, length); @@ -1233,11 +1290,15 @@ restart_poll: if (iph->check == 0xffff) { iph->check = 0; iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); - adapter->rx_large_packets++; } } } + if (length > netdev->mtu + ETH_HLEN) { + ibmveth_rx_mss_helper(skb, mss, lrg_pkt); + adapter->rx_large_packets++; + } + napi_gro_receive(napi, skb); /* send it up */ netdev->stats.rx_packets++; diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index 4eade67..7acda04 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h @@ -209,6 +209,7 @@ struct ibmveth_rx_q_entry { #define IBMVETH_RXQ_TOGGLE 0x80000000 #define IBMVETH_RXQ_TOGGLE_SHIFT 31 #define IBMVETH_RXQ_VALID 0x40000000 +#define IBMVETH_RXQ_LRG_PKT 0x04000000 #define IBMVETH_RXQ_NO_CSUM 0x02000000 #define IBMVETH_RXQ_CSUM_GOOD 0x01000000 #define IBMVETH_RXQ_OFF_MASK 0x0000FFFF