ipv6: hash net ptr into fragmentation bucket selection [Linux 3.16.72]

This Linux kernel change "ipv6: hash net ptr into fragmentation bucket selection" is included in the Linux 3.16.72 release. This change is authored by Hannes Frederic Sowa <hannes [at] stressinduktion.org> on Wed Mar 25 17:07:45 2015 +0100. The commit for this change in Linux stable tree is 6caabe4 (patch) which is from upstream commit 5a352dd. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 5a352dd.

ipv6: hash net ptr into fragmentation bucket selection

commit 5a352dd0a3aac03b443c94828dfd7144261c8636 upstream.

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 <[email protected]>
Cc: Flavio Leitner <[email protected]>
Signed-off-by: Hannes Frederic Sowa <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Ben Hutchings <[email protected]>

There are 29 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 include/net/ipv6.h     |  5 +++--
 net/ipv6/ip6_output.c  |  6 +++---
 net/ipv6/output_core.c | 14 ++++++++------
 net/ipv6/udp_offload.c |  4 ++--
 4 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 0ebd9e3..c4e455f 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -688,8 +688,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);

diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 6780c45..1e68db0 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -632,7 +632,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);
@@ -785,7 +785,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
        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:
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
index 9505567..b1986ac 100644
--- a/net/ipv6/output_core.c
+++ b/net/ipv6/output_core.c
@@ -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);
 }
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index 18db8cf..28d0235 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -77,7 +77,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;
@@ -125,7 +125,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

Leave a Reply

Your email address will not be published. Required fields are marked *