inetpeer: get rid of ip_id_count
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / route.c
index d35bbf0cf4045d04f67d30e31f15c5271058dd5a..da2d4efc0bf74a0978e4d8f866d799dacd1686ce 100644 (file)
@@ -89,6 +89,7 @@
 #include <linux/rcupdate.h>
 #include <linux/times.h>
 #include <linux/slab.h>
+#include <linux/jhash.h>
 #include <net/dst.h>
 #include <net/net_namespace.h>
 #include <net/protocol.h>
@@ -464,39 +465,23 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
        return neigh_create(&arp_tbl, pkey, dev);
 }
 
-/*
- * Peer allocation may fail only in serious out-of-memory conditions.  However
- * we still can generate some output.
- * Random ID selection looks a bit dangerous because we have no chances to
- * select ID being unique in a reasonable period of time.
- * But broken packet identifier may be better than no packet at all.
- */
-static void ip_select_fb_ident(struct iphdr *iph)
-{
-       static DEFINE_SPINLOCK(ip_fb_id_lock);
-       static u32 ip_fallback_id;
-       u32 salt;
-
-       spin_lock_bh(&ip_fb_id_lock);
-       salt = secure_ip_id((__force __be32)ip_fallback_id ^ iph->daddr);
-       iph->id = htons(salt & 0xFFFF);
-       ip_fallback_id = salt;
-       spin_unlock_bh(&ip_fb_id_lock);
-}
+atomic_t *ip_idents __read_mostly;
+EXPORT_SYMBOL(ip_idents);
 
-void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
+void __ip_select_ident(struct iphdr *iph, int segs)
 {
-       struct net *net = dev_net(dst->dev);
-       struct inet_peer *peer;
+       static u32 ip_idents_hashrnd __read_mostly;
+       static bool hashrnd_initialized = false;
+       u32 hash, id;
 
-       peer = inet_getpeer_v4(net->ipv4.peers, iph->daddr, 1);
-       if (peer) {
-               iph->id = htons(inet_getid(peer, more));
-               inet_putpeer(peer);
-               return;
+       if (unlikely(!hashrnd_initialized)) {
+               hashrnd_initialized = true;
+               get_random_bytes(&ip_idents_hashrnd, sizeof(ip_idents_hashrnd));
        }
 
-       ip_select_fb_ident(iph);
+       hash = jhash_1word((__force u32)iph->daddr, ip_idents_hashrnd);
+       id = ip_idents_reserve(hash, segs);
+       iph->id = htons(id);
 }
 EXPORT_SYMBOL(__ip_select_ident);
 
@@ -985,20 +970,21 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
        const struct iphdr *iph = (const struct iphdr *) skb->data;
        struct flowi4 fl4;
        struct rtable *rt;
-       struct dst_entry *dst;
+       struct dst_entry *odst = NULL;
        bool new = false;
 
        bh_lock_sock(sk);
-       rt = (struct rtable *) __sk_dst_get(sk);
+       odst = sk_dst_get(sk);
 
-       if (sock_owned_by_user(sk) || !rt) {
+       if (sock_owned_by_user(sk) || !odst) {
                __ipv4_sk_update_pmtu(skb, sk, mtu);
                goto out;
        }
 
        __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0);
 
-       if (!__sk_dst_check(sk, 0)) {
+       rt = (struct rtable *)odst;
+       if (odst->obsolete && odst->ops->check(odst, 0) == NULL) {
                rt = ip_route_output_flow(sock_net(sk), &fl4, sk);
                if (IS_ERR(rt))
                        goto out;
@@ -1008,8 +994,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
 
        __ip_rt_update_pmtu((struct rtable *) rt->dst.path, &fl4, mtu);
 
-       dst = dst_check(&rt->dst, 0);
-       if (!dst) {
+       if (!dst_check(&rt->dst, 0)) {
                if (new)
                        dst_release(&rt->dst);
 
@@ -1021,10 +1006,11 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
        }
 
        if (new)
-               __sk_dst_set(sk, &rt->dst);
+               sk_dst_set(sk, &rt->dst);
 
 out:
        bh_unlock_sock(sk);
+       dst_release(odst);
 }
 EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu);
 
@@ -1478,7 +1464,7 @@ static int __mkroute_input(struct sk_buff *skb,
        struct in_device *out_dev;
        unsigned int flags = 0;
        bool do_cache;
-       u32 itag;
+       u32 itag = 0;
 
        /* get a working reference to the output device */
        out_dev = __in_dev_get_rcu(FIB_RES_DEV(*res));
@@ -1544,6 +1530,7 @@ static int __mkroute_input(struct sk_buff *skb,
        rth->rt_gateway = 0;
        rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
+       RT_CACHE_STAT_INC(in_slow_tot);
 
        rth->dst.input = ip_forward;
        rth->dst.output = ip_output;
@@ -1645,8 +1632,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        if (err != 0)
                goto no_route;
 
-       RT_CACHE_STAT_INC(in_slow_tot);
-
        if (res.type == RTN_BROADCAST)
                goto brd_input;
 
@@ -1715,13 +1700,18 @@ local_input:
        rth->rt_gateway = 0;
        rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
+       RT_CACHE_STAT_INC(in_slow_tot);
        if (res.type == RTN_UNREACHABLE) {
                rth->dst.input= ip_error;
                rth->dst.error= -err;
                rth->rt_flags   &= ~RTCF_LOCAL;
        }
-       if (do_cache)
-               rt_cache_route(&FIB_RES_NH(res), rth);
+       if (do_cache) {
+               if (unlikely(!rt_cache_route(&FIB_RES_NH(res), rth))) {
+                       rth->dst.flags |= DST_NOCACHE;
+                       rt_add_uncached_list(rth);
+               }
+       }
        skb_dst_set(skb, &rth->dst);
        err = 0;
        goto out;
@@ -2020,7 +2010,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
                                                              RT_SCOPE_LINK);
                        goto make_route;
                }
-               if (fl4->saddr) {
+               if (!fl4->saddr) {
                        if (ipv4_is_multicast(fl4->daddr))
                                fl4->saddr = inet_select_addr(dev_out, 0,
                                                              fl4->flowi4_scope);
@@ -2302,7 +2292,7 @@ static int rt_fill_info(struct net *net,  __be32 dst, __be32 src,
                        }
                } else
 #endif
-                       if (nla_put_u32(skb, RTA_IIF, rt->rt_iif))
+                       if (nla_put_u32(skb, RTA_IIF, skb->dev->ifindex))
                                goto nla_put_failure;
        }
 
@@ -2651,6 +2641,12 @@ int __init ip_rt_init(void)
 {
        int rc = 0;
 
+       ip_idents = kmalloc(IP_IDENTS_SZ * sizeof(*ip_idents), GFP_KERNEL);
+       if (!ip_idents)
+               panic("IP: failed to allocate ip_idents\n");
+
+       prandom_bytes(ip_idents, IP_IDENTS_SZ * sizeof(*ip_idents));
+
 #ifdef CONFIG_IP_ROUTE_CLASSID
        ip_rt_acct = __alloc_percpu(256 * sizeof(struct ip_rt_acct), __alignof__(struct ip_rt_acct));
        if (!ip_rt_acct)