IP_GRE: Fix IP-Identification.
authorPravin B Shelar <pshelar@nicira.com>
Fri, 22 Feb 2013 07:30:30 +0000 (07:30 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 25 Feb 2013 20:47:41 +0000 (15:47 -0500)
GRE-GSO generates ip fragments with id 0,2,3,4... for every
GSO packet, which is not correct. Following patch fixes it
by setting ip-header id unique id of fragments are allowed.
As Eric Dumazet suggested it is optimized by using inner ip-header
whenever inner packet is ipv4.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ipip.h
net/ipv4/af_inet.c
net/ipv4/ip_gre.c

index 21947cf..fd19625 100644 (file)
@@ -71,4 +71,21 @@ static inline void iptunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 }
 
+static inline void tunnel_ip_select_ident(struct sk_buff *skb,
+                                         const struct iphdr  *old_iph,
+                                         struct dst_entry *dst)
+{
+       struct iphdr *iph = ip_hdr(skb);
+
+       if (iph->frag_off & htons(IP_DF))
+               iph->id = 0;
+       else {
+               /* Use inner packet iph-id if possible. */
+               if (skb->protocol == htons(ETH_P_IP) && old_iph->id)
+                       iph->id = old_iph->id;
+               else
+                       __ip_select_ident(iph, dst,
+                                         (skb_shinfo(skb)->gso_segs ?: 1) - 1);
+       }
+}
 #endif
index 15847e1..68f6a94 100644 (file)
@@ -1332,8 +1332,10 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
                        if (skb->next != NULL)
                                iph->frag_off |= htons(IP_MF);
                        offset += (skb->len - skb->mac_len - iph->ihl * 4);
-               } else
-                       iph->id = htons(id++);
+               } else  {
+                       if (!(iph->frag_off & htons(IP_DF)))
+                               iph->id = htons(id++);
+               }
                iph->tot_len = htons(skb->len - skb->mac_len);
                iph->check = 0;
                iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
index 5ef4da7..b8bada0 100644 (file)
@@ -970,7 +970,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
        iph->daddr              =       fl4.daddr;
        iph->saddr              =       fl4.saddr;
        iph->ttl                =       ttl;
-       iph->id                 =       0;
+
+       tunnel_ip_select_ident(skb, old_iph, &rt->dst);
 
        if (ttl == 0) {
                if (skb->protocol == htons(ETH_P_IP))