Skip to content

Commit

Permalink
ipv6: hash net ptr into fragmentation bucket selection
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Hannes Frederic Sowa authored and David S. Miller committed Mar 25, 2015
1 parent b6a7719 commit 5a352dd
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 13 deletions.
5 changes: 3 additions & 2 deletions include/net/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
6 changes: 3 additions & 3 deletions net/ipv6/ip6_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -775,7 +775,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;
Expand Down Expand Up @@ -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:
Expand Down
14 changes: 8 additions & 6 deletions net/ipv6/output_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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];
Expand All @@ -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);
}
Expand Down
4 changes: 2 additions & 2 deletions net/ipv6/udp_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 5a352dd

Please sign in to comment.