ipv4: hash net ptr into fragmentation bucket selection

commit b6a7719aedd7e5c0f2df7641aa47386111682df4 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>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Kevin F. Haggerty <haggertk@lineageos.org>
Change-Id: I7d76a6f5820ae05a159c8207fe52a6e58db6f024
This commit is contained in:
Hannes Frederic Sowa 2015-03-25 17:07:44 +01:00 committed by matteo0026
parent 051e59e292
commit bd64ab13d1
10 changed files with 26 additions and 20 deletions

View File

@ -281,7 +281,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
nf_reset(skb);
skb->ip_summed = CHECKSUM_NONE;
ip_select_ident(skb, NULL);
ip_select_ident(sock_net(sk), skb, NULL);
ip_send_check(iph);
ip_local_out(skb);

View File

@ -271,9 +271,10 @@ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst)
}
u32 ip_idents_reserve(u32 hash, int segs);
void __ip_select_ident(struct iphdr *iph, int segs);
void __ip_select_ident(struct net *net, struct iphdr *iph, int segs);
static inline void ip_select_ident_segs(struct sk_buff *skb, struct sock *sk, int segs)
static inline void ip_select_ident_segs(struct net *net, struct sk_buff *skb,
struct sock *sk, int segs)
{
struct iphdr *iph = ip_hdr(skb);
@ -290,13 +291,14 @@ static inline void ip_select_ident_segs(struct sk_buff *skb, struct sock *sk, in
iph->id = 0;
}
} else {
__ip_select_ident(iph, segs);
__ip_select_ident(net, iph, segs);
}
}
static inline void ip_select_ident(struct sk_buff *skb, struct sock *sk)
static inline void ip_select_ident(struct net *net, struct sk_buff *skb,
struct sock *sk)
{
ip_select_ident_segs(skb, sk, 1);
ip_select_ident_segs(net, skb, sk, 1);
}
/*

View File

@ -3,6 +3,7 @@
#include <linux/if_tunnel.h>
#include <net/ip.h>
#include <net/ip_vs.h>
/* Keep error state on tunnel for 30 sec */
#define IPTUNNEL_ERR_TIMEO (30*HZ)
@ -50,7 +51,7 @@ struct ip_tunnel_prl_entry {
int pkt_len = skb->len - skb_transport_offset(skb); \
\
skb->ip_summed = CHECKSUM_NONE; \
ip_select_ident(skb, NULL); \
ip_select_ident(skb_net(skb), skb, NULL); \
\
err = ip_local_out(skb); \
if (likely(net_xmit_eval(err) == 0)) { \

View File

@ -343,7 +343,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
pip->saddr = fl4.saddr;
pip->protocol = IPPROTO_IGMP;
pip->tot_len = 0; /* filled in later */
ip_select_ident(skb, NULL);
ip_select_ident(net, skb, NULL);
((u8*)&pip[1])[0] = IPOPT_RA;
((u8*)&pip[1])[1] = 4;
((u8*)&pip[1])[2] = 0;
@ -687,7 +687,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
iph->daddr = dst;
iph->saddr = fl4.saddr;
iph->protocol = IPPROTO_IGMP;
ip_select_ident(skb, NULL);
ip_select_ident(net, skb, NULL);
((u8*)&iph[1])[0] = IPOPT_RA;
((u8*)&iph[1])[1] = 4;
((u8*)&iph[1])[2] = 0;

View File

@ -161,7 +161,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr);
iph->saddr = saddr;
iph->protocol = sk->sk_protocol;
ip_select_ident(skb, sk);
ip_select_ident(sock_net(sk), skb, sk);
if (opt && opt->opt.optlen) {
iph->ihl += opt->opt.optlen>>2;
@ -403,7 +403,8 @@ packet_routed:
ip_options_build(skb, &inet_opt->opt, inet->inet_daddr, rt, 0);
}
ip_select_ident_segs(skb, sk, skb_shinfo(skb)->gso_segs ?: 1);
ip_select_ident_segs(sock_net(sk), skb, sk,
skb_shinfo(skb)->gso_segs ?: 1);
skb->priority = sk->sk_priority;
skb->mark = sk->sk_mark;
@ -1354,7 +1355,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
iph->ttl = ttl;
iph->protocol = sk->sk_protocol;
ip_copy_addrs(iph, fl4);
ip_select_ident(skb, sk);
ip_select_ident(net, skb, sk);
if (opt) {
iph->ihl += opt->optlen>>2;

View File

@ -1557,7 +1557,8 @@ static struct notifier_block ip_mr_notifier = {
* important for multicast video.
*/
static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
static void ip_encap(struct net *net, struct sk_buff *skb,
__be32 saddr, __be32 daddr)
{
struct iphdr *iph;
const struct iphdr *old_iph = ip_hdr(skb);
@ -1576,7 +1577,7 @@ static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
iph->protocol = IPPROTO_IPIP;
iph->ihl = 5;
iph->tot_len = htons(skb->len);
ip_select_ident(skb, NULL);
ip_select_ident(net, skb, NULL);
ip_send_check(iph);
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
@ -1672,7 +1673,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
* What do we do with netfilter? -- RR
*/
if (vif->flags & VIFF_TUNNEL) {
ip_encap(skb, vif->local, vif->remote);
ip_encap(net, skb, vif->local, vif->remote);
/* FIXME: extra output firewall step used to be here. --RR */
vif->dev->stats.tx_packets++;
vif->dev->stats.tx_bytes += skb->len;

View File

@ -397,7 +397,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
iph->check = 0;
iph->tot_len = htons(length);
if (!iph->id)
ip_select_ident(skb, NULL);
ip_select_ident(net, skb, NULL);
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
}

View File

@ -1398,7 +1398,7 @@ u32 ip_idents_reserve(u32 hash, int segs)
}
EXPORT_SYMBOL(ip_idents_reserve);
void __ip_select_ident(struct iphdr *iph, int segs)
void __ip_select_ident(struct net *net, struct iphdr *iph, int segs)
{
static u32 ip_idents_hashrnd __read_mostly;
static bool hashrnd_initialized = false;
@ -1411,7 +1411,7 @@ void __ip_select_ident(struct iphdr *iph, int segs)
hash = jhash_3words((__force u32)iph->daddr,
(__force u32)iph->saddr,
iph->protocol,
iph->protocol ^ net_hash_mix(net),
ip_idents_hashrnd);
id = ip_idents_reserve(hash, segs);
iph->id = htons(id);

View File

@ -59,7 +59,7 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
top_iph->saddr = x->props.saddr.a4;
top_iph->daddr = x->id.daddr.a4;
ip_select_ident(skb, NULL);
ip_select_ident(dev_net(dst->dev), skb, NULL);
return 0;
}

View File

@ -780,6 +780,7 @@ int
ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp)
{
struct net *net = skb_net(skb);
struct rtable *rt; /* Route to the other host */
__be32 saddr; /* Source for tunnel */
struct net_device *tdev; /* Device to other host */
@ -867,7 +868,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
iph->daddr = cp->daddr.ip;
iph->saddr = saddr;
iph->ttl = old_iph->ttl;
ip_select_ident(skb, NULL);
ip_select_ident(net, skb, NULL);
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;