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 <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>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Kevin F. Haggerty <haggertk@lineageos.org>
Change-Id: I4cd053112b178ddb0e0efbd1282478075dd064cb
This commit is contained in:
Hannes Frederic Sowa 2015-03-25 17:07:45 +01:00 committed by matteo0026
parent b3c791b3a6
commit 8d0da84afe
5 changed files with 12 additions and 9 deletions

View File

@ -580,7 +580,7 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
case VIRTIO_NET_HDR_GSO_UDP:
gso_type = SKB_GSO_UDP;
if (skb->protocol == htons(ETH_P_IPV6))
ipv6_proxy_select_ident(skb);
ipv6_proxy_select_ident(dev_net(skb->dev), skb);
break;
default:
return -EINVAL;

View File

@ -720,7 +720,7 @@ static ssize_t tun_get_user(struct tun_struct *tun,
case VIRTIO_NET_HDR_GSO_UDP:
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
if (skb->protocol == htons(ETH_P_IPV6))
ipv6_proxy_select_ident(skb);
ipv6_proxy_select_ident(dev_net(skb->dev), skb);
break;
default:
tun->dev->stats.rx_frame_errors++;

View File

@ -526,8 +526,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));
}
extern void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt);
void ipv6_proxy_select_ident(struct sk_buff *skb);
extern 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);
/*
* Prototypes exported by ipv6

View File

@ -602,7 +602,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
return -EINVAL;
}
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;
static bool hashrnd_initialized = false;
@ -614,6 +614,7 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
}
hash = __ipv6_addr_jhash(&rt->rt6i_dst.addr, ip6_idents_hashrnd);
hash = __ipv6_addr_jhash(&rt->rt6i_src.addr, hash);
hash ^= net_hash_mix(net);
id = ip_idents_reserve(hash, 1);
fhdr->identification = htonl(id);
@ -710,7 +711,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);
@ -859,7 +860,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;
@ -1160,7 +1161,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;
__skb_queue_tail(&sk->sk_write_queue, skb);
}

View File

@ -9,7 +9,7 @@
* This is similar to ipv6_select_ident() but we use an independent hash
* seed to limit information leakage.
*/
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;
static bool hashrnd_initialized = false;
@ -31,6 +31,7 @@ void ipv6_proxy_select_ident(struct sk_buff *skb)
}
hash = __ipv6_addr_jhash(&addrs[1], ip6_proxy_idents_hashrnd);
hash = __ipv6_addr_jhash(&addrs[0], hash);
hash ^= net_hash_mix(net);
id = ip_idents_reserve(hash, 1);
skb_shinfo(skb)->ip6_frag_id = htonl(id);