diff options
author | Eric Dumazet <edumazet@google.com> | 2013-01-25 15:34:37 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-28 00:27:15 -0500 |
commit | cef401de7be8c4e155c6746bfccf721a4fa5fab9 (patch) | |
tree | af082329bf0613ed9de5b9575e3f94f3f03b77ec /net/ipv4/ip_gre.c | |
parent | 61550022b9586972082904b80de26a464c558437 (diff) |
net: fix possible wrong checksum generation
Pravin Shelar mentioned that GSO could potentially generate
wrong TX checksum if skb has fragments that are overwritten
by the user between the checksum computation and transmit.
He suggested to linearize skbs but this extra copy can be
avoided for normal tcp skbs cooked by tcp_sendmsg().
This patch introduces a new SKB_GSO_SHARED_FRAG flag, set
in skb_shinfo(skb)->gso_type if at least one frag can be
modified by the user.
Typical sources of such possible overwrites are {vm}splice(),
sendfile(), and macvtap/tun/virtio_net drivers.
Tested:
$ netperf -H 7.7.8.84
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to
7.7.8.84 () port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 3959.52
$ netperf -H 7.7.8.84 -t TCP_SENDFILE
TCP SENDFILE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 7.7.8.84 ()
port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 3216.80
Performance of the SENDFILE is impacted by the extra allocation and
copy, and because we use order-0 pages, while the TCP_STREAM uses
bigger pages.
Reported-by: Pravin Shelar <pshelar@nicira.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ip_gre.c')
-rw-r--r-- | net/ipv4/ip_gre.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 303012adf9e6..af6be70821c4 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -738,7 +738,7 @@ drop: | |||
738 | static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | 738 | static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) |
739 | { | 739 | { |
740 | struct ip_tunnel *tunnel = netdev_priv(dev); | 740 | struct ip_tunnel *tunnel = netdev_priv(dev); |
741 | const struct iphdr *old_iph = ip_hdr(skb); | 741 | const struct iphdr *old_iph; |
742 | const struct iphdr *tiph; | 742 | const struct iphdr *tiph; |
743 | struct flowi4 fl4; | 743 | struct flowi4 fl4; |
744 | u8 tos; | 744 | u8 tos; |
@@ -756,6 +756,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev | |||
756 | skb_checksum_help(skb)) | 756 | skb_checksum_help(skb)) |
757 | goto tx_error; | 757 | goto tx_error; |
758 | 758 | ||
759 | old_iph = ip_hdr(skb); | ||
760 | |||
759 | if (dev->type == ARPHRD_ETHER) | 761 | if (dev->type == ARPHRD_ETHER) |
760 | IPCB(skb)->flags = 0; | 762 | IPCB(skb)->flags = 0; |
761 | 763 | ||