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 21947cf4fa4678f5cb301ec29ddb65b74492a6d6..fd19625ff99db290fd289b3caf18f32c9b72ffc3 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 15847e19b7ddc55b5d7b0ca81ba1f092d9ef54bd..68f6a94f7661999095d9a02539aee956cd52e8cc 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 5ef4da780ac1120f6e2ab8239b077f79c6720dc8..b8bada00d516e134c3856351d993d22819f2d373 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))