ipv6: hash net ptr into fragmentation bucket selection
authorHannes Frederic Sowa <hannes@stressinduktion.org>
Wed, 25 Mar 2015 16:07:45 +0000 (17:07 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 25 Mar 2015 18:07:04 +0000 (14:07 -0400)
As namespaces are sometimes used with overlapping ip address ranges,
we should also use the namespace as input to the hash to select the ip
fragmentation counter bucket.

Cc: Eric Dumazet <edumazet@google.com>
Cc: Flavio Leitner <fbl@redhat.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ipv6.h
net/ipv6/ip6_output.c
net/ipv6/output_core.c
net/ipv6/udp_offload.c

index e7ba975..65142e6 100644 (file)
@@ -671,8 +671,9 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add
        return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
 }
 
-void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
-void ipv6_proxy_select_ident(struct sk_buff *skb);
+void ipv6_select_ident(struct net *net, struct frag_hdr *fhdr,
+                      struct rt6_info *rt);
+void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb);
 
 int ip6_dst_hoplimit(struct dst_entry *dst);
 
index 7e80b61..b06ad00 100644 (file)
@@ -628,7 +628,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                skb_reset_network_header(skb);
                memcpy(skb_network_header(skb), tmp_hdr, hlen);
 
-               ipv6_select_ident(fh, rt);
+               ipv6_select_ident(net, fh, rt);
                fh->nexthdr = nexthdr;
                fh->reserved = 0;
                fh->frag_off = htons(IP6_MF);
@@ -775,7 +775,7 @@ slow_path:
                fh->nexthdr = nexthdr;
                fh->reserved = 0;
                if (!frag_id) {
-                       ipv6_select_ident(fh, rt);
+                       ipv6_select_ident(net, fh, rt);
                        frag_id = fh->identification;
                } else
                        fh->identification = frag_id;
@@ -1079,7 +1079,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
        skb_shinfo(skb)->gso_size = (mtu - fragheaderlen -
                                     sizeof(struct frag_hdr)) & ~7;
        skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
-       ipv6_select_ident(&fhdr, rt);
+       ipv6_select_ident(sock_net(sk), &fhdr, rt);
        skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
 
 append:
index 74581f7..4016a6e 100644 (file)
@@ -9,13 +9,14 @@
 #include <net/addrconf.h>
 #include <net/secure_seq.h>
 
-static u32 __ipv6_select_ident(u32 hashrnd, struct in6_addr *dst,
-                              struct in6_addr *src)
+static u32 __ipv6_select_ident(struct net *net, u32 hashrnd,
+                              struct in6_addr *dst, struct in6_addr *src)
 {
        u32 hash, id;
 
        hash = __ipv6_addr_jhash(dst, hashrnd);
        hash = __ipv6_addr_jhash(src, hash);
+       hash ^= net_hash_mix(net);
 
        /* Treat id of 0 as unset and if we get 0 back from ip_idents_reserve,
         * set the hight order instead thus minimizing possible future
@@ -36,7 +37,7 @@ static u32 __ipv6_select_ident(u32 hashrnd, struct in6_addr *dst,
  *
  * The network header must be set before calling this.
  */
-void ipv6_proxy_select_ident(struct sk_buff *skb)
+void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb)
 {
        static u32 ip6_proxy_idents_hashrnd __read_mostly;
        struct in6_addr buf[2];
@@ -53,20 +54,21 @@ void ipv6_proxy_select_ident(struct sk_buff *skb)
        net_get_random_once(&ip6_proxy_idents_hashrnd,
                            sizeof(ip6_proxy_idents_hashrnd));
 
-       id = __ipv6_select_ident(ip6_proxy_idents_hashrnd,
+       id = __ipv6_select_ident(net, ip6_proxy_idents_hashrnd,
                                 &addrs[1], &addrs[0]);
        skb_shinfo(skb)->ip6_frag_id = htonl(id);
 }
 EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
 
-void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
+void ipv6_select_ident(struct net *net, struct frag_hdr *fhdr,
+                      struct rt6_info *rt)
 {
        static u32 ip6_idents_hashrnd __read_mostly;
        u32 id;
 
        net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd));
 
-       id = __ipv6_select_ident(ip6_idents_hashrnd, &rt->rt6i_dst.addr,
+       id = __ipv6_select_ident(net, ip6_idents_hashrnd, &rt->rt6i_dst.addr,
                                 &rt->rt6i_src.addr);
        fhdr->identification = htonl(id);
 }
index be2c0ba..7441e1e 100644 (file)
@@ -54,7 +54,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
 
                /* Set the IPv6 fragment id if not set yet */
                if (!skb_shinfo(skb)->ip6_frag_id)
-                       ipv6_proxy_select_ident(skb);
+                       ipv6_proxy_select_ident(dev_net(skb->dev), skb);
 
                segs = NULL;
                goto out;
@@ -113,7 +113,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                fptr->nexthdr = nexthdr;
                fptr->reserved = 0;
                if (!skb_shinfo(skb)->ip6_frag_id)
-                       ipv6_proxy_select_ident(skb);
+                       ipv6_proxy_select_ident(dev_net(skb->dev), skb);
                fptr->identification = skb_shinfo(skb)->ip6_frag_id;
 
                /* Fragment the skb. ipv6 header and the remaining fields of the