]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ipv4: hash net ptr into fragmentation bucket selection
authorHannes Frederic Sowa <hannes@stressinduktion.org>
Wed, 25 Mar 2015 16:07:44 +0000 (17:07 +0100)
committerBen Hutchings <ben@decadent.org.uk>
Tue, 13 Aug 2019 11:39:30 +0000 (12:39 +0100)
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>
drivers/net/ppp/pptp.c
include/net/ip.h
net/ipv4/igmp.c
net/ipv4/ip_output.c
net/ipv4/ip_tunnel_core.c
net/ipv4/ipmr.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/xfrm4_mode_tunnel.c
net/netfilter/ipvs/ip_vs_xmit.c

index 5dd0fe1635b9d977bfa0d908281a508666aab142..a97b207735083c5dcf5d2300b1cb994eddad0600 100644 (file)
@@ -284,7 +284,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);
index 27dd9826e05d867fa7abafeb46aab76f5432af2b..8ec53320c902bb45007a84fb785ed778aa68436b 100644 (file)
@@ -319,9 +319,10 @@ static inline unsigned int ip_skb_dst_mtu(const struct sk_buff *skb)
 }
 
 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);
 
@@ -338,13 +339,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);
 }
 
 static inline __wsum inet_compute_pseudo(struct sk_buff *skb, int proto)
index 48444c4c3c51a3295f33776a53111135c6e53658..680ce5f4fb65da4942ba73dee0f979be9351afcf 100644 (file)
@@ -395,7 +395,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
 
        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;
@@ -739,7 +739,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;
index 109eddf0248afdfc705f11b8b544eeae864d1615..2a05dfc9a35e313e6b842cfc6b3d60a976aad169 100644 (file)
@@ -150,7 +150,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;
@@ -432,7 +432,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);
 
        /* TODO : should we use skb->sk here instead of sk ? */
        skb->priority = sk->sk_priority;
@@ -1385,7 +1386,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;
index 88c386cf7d85a985b9bd0aca11d3528347aea152..8c4dcc46acd2932e062faf546331c938b160b0d1 100644 (file)
@@ -74,7 +74,7 @@ int iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
        iph->daddr      =       dst;
        iph->saddr      =       src;
        iph->ttl        =       ttl;
-       __ip_select_ident(iph, skb_shinfo(skb)->gso_segs ?: 1);
+       __ip_select_ident(sock_net(sk), iph, skb_shinfo(skb)->gso_segs ?: 1);
 
        err = ip_local_out_sk(sk, skb);
        if (unlikely(net_xmit_eval(err)))
index 643ec0bb80a57b71ef3eb400740e6866e40a685d..5859c0f5bd417743a71efd5e12b0dade3b3354d1 100644 (file)
@@ -1647,7 +1647,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);
@@ -1666,7 +1667,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));
@@ -1763,7 +1764,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;
index e43a585abb35f7dfa69e841be3798a6e08f76b14..04700c745ca0b6854d535b6cfd8d16505c8a67c3 100644 (file)
@@ -399,7 +399,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);
        }
index 236c6c6134d11b7badd39a3cca27932cb813971e..5092304f31fba553955d3b50dc8f4a3b922d2903 100644 (file)
@@ -484,7 +484,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;
        u32 hash, id;
@@ -493,7 +493,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);
index 91771a7c802f828c33429413674c5f78ca393b6f..35feda67646494c92263cf30109432fb395fa1df 100644 (file)
@@ -63,7 +63,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;
 }
index 7abd786d9d893d7810c9bad6bbb6d0820edc72e6..44fa945ed6b4ffde55cc7f84aef053af01a19d9d 100644 (file)
@@ -813,7 +813,8 @@ int
 ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
                  struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
 {
-       struct netns_ipvs *ipvs = net_ipvs(skb_net(skb));
+       struct net *net = skb_net(skb);
+       struct netns_ipvs *ipvs = net_ipvs(net);
        struct rtable *rt;                      /* Route to the other host */
        __be32 saddr;                           /* Source for tunnel */
        struct net_device *tdev;                /* Device to other host */
@@ -882,7 +883,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->ignore_df = 1;