[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#630730: linux-image-2.6.32: GSO IPv6 issues



Package: linux-2.6
Version: 2.6.32-34squeeze1
Severity: normal
Tags: patch

Hi,

While performing stress testing on a KVM instance with IPv6, we noticed very
poor performance on IPv6 TCP connections, which basically came down to the bug
fixed by upstream commit 8e1e8a4779cb23c1d9f51e9223795e07ec54d77a[1]. Both, the
host and the guest were running 2.6.32-5-amd64 2.6.32-31 and the host featured
Intel NICs, using e1000e and igb. SSH sessions to the guest from outside would
effectively stall when large output was generated (e.g. ls -lR /) and 
the problem would disappear when disabling virtio_net's gso (modprobe 
virtio_net gso=0) or disabling the host's TSO using ethtool.

Furthermore, while trying to reproduce the behaviour on another system, we
triggered the bug fixed by commit 0aa68271510ae2b221d4b60892103837be63afe4[2],
i.e. a routed (not bridged) KVM instance using virtio-net would not get its GSO
IPv6 packets forwarded to the network, with the same poor performance as above.

After backporting and applying both patches to squeeze's version, IPv6 
performance was restored to the same levels as IPv4 in both cases. You 
can find the backported versions of the patches attached.

Thanks,
Apollon

[1] http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=8e1e8a4779cb23c1d9f51e9223795e07ec54d77a
[2] http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=0aa68271510ae2b221d4b60892103837be63afe4


-- Package-specific info:
** Version:
Linux version 2.6.32-5-amd64 (Debian 2.6.32-31) (ben@decadent.org.uk) (gcc version 4.3.5 (Debian 4.3.5-4) ) #1 SMP Mon Mar 7 21:35:22 UTC 2011

** Command line:
BOOT_IMAGE=/vmlinuz-2.6.32-5-amd64 root=/dev/mapper/linux-root ro

** Not tainted
>From d70ca6cd8f33d4cb2fba194fc520232278f0d6a1 Mon Sep 17 00:00:00 2001
From: Sridhar Samudrala <sri@us.ibm.com>
Date: Thu, 16 Jun 2011 15:52:35 +0300
Subject: [PATCH 1/2] net: Fix IPv6 GSO type checks in Intel ethernet drivers

Found this problem when testing IPv6 from a KVM guest to a remote
host via e1000e device on the host.
The following patch fixes the check for IPv6 GSO packet in Intel
ethernet drivers to use skb_is_gso_v6(). SKB_GSO_DODGY is also set
when packets are forwarded from a guest.

Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/e1000e/netdev.c    |    2 +-
 drivers/net/igb/igb_main.c     |    2 +-
 drivers/net/igbvf/netdev.c     |    2 +-
 drivers/net/ixgbe/ixgbe_main.c |    2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 4920a4e..92d6621 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -3807,7 +3807,7 @@ static int e1000_tso(struct e1000_adapter *adapter,
 								 0);
 			cmd_length = E1000_TXD_CMD_IP;
 			ipcse = skb_transport_offset(skb) - 1;
-		} else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+		} else if (skb_is_gso_v6(skb)) {
 			ipv6_hdr(skb)->payload_len = 0;
 			tcp_hdr(skb)->check =
 				~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 9e3d87a..40dc84c 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -3032,7 +3032,7 @@ static inline int igb_tso_adv(struct igb_adapter *adapter,
 							 iph->daddr, 0,
 							 IPPROTO_TCP,
 							 0);
-	} else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+	} else if (skb_is_gso_v6(skb)) {
 		ipv6_hdr(skb)->payload_len = 0;
 		tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
 						       &ipv6_hdr(skb)->daddr,
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 91024a3..d29188f 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -1953,7 +1953,7 @@ static int igbvf_tso(struct igbvf_adapter *adapter,
 		                                         iph->daddr, 0,
 		                                         IPPROTO_TCP,
 		                                         0);
-	} else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+	} else if (skb_is_gso_v6(skb)) {
 		ipv6_hdr(skb)->payload_len = 0;
 		tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
 		                                       &ipv6_hdr(skb)->daddr,
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index a550d37..6810149 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -4881,7 +4881,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
 			                                         IPPROTO_TCP,
 			                                         0);
 			adapter->hw_tso_ctxt++;
-		} else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+		} else if (skb_is_gso_v6(skb)) {
 			ipv6_hdr(skb)->payload_len = 0;
 			tcp_hdr(skb)->check =
 			    ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-- 
1.7.2.5

>From cc775a4f3c7275b0de898be2be245741b5353c8f Mon Sep 17 00:00:00 2001
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Thu, 16 Jun 2011 17:59:11 +0300
Subject: [PATCH 2/2] ipv6: Add GSO support on forwarding path

Currently we disallow GSO packets on the IPv6 forward path.
This patch fixes this.

Note that I discovered that our existing GSO MTU checks (e.g.,
IPv4 forwarding) are buggy in that they skip the check altogether,
when they really should be checking gso_size + header instead.

I have also been lazy here in that I haven't bothered to segment
the GSO packet by hand before generating an ICMP message.  Someone
should add that to be 100% correct.

Reported-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv6/ip6_output.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index eca3ef7..9ad5792 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -510,7 +510,7 @@ int ip6_forward(struct sk_buff *skb)
 		}
 	}
 
-	if (skb->len > dst_mtu(dst)) {
+	if (skb->len > dst_mtu(dst) && !skb_is_gso(skb)) {
 		/* Again, force OUTPUT device used as source address */
 		skb->dev = dst->dev;
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev);
-- 
1.7.2.5


Reply to: