Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
authorDavid S. Miller <davem@davemloft.net>
Mon, 28 Nov 2016 01:21:48 +0000 (20:21 -0500)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Nov 2016 01:21:48 +0000 (20:21 -0500)
Steffen Klassert says:

====================
pull request (net): ipsec 2016-11-25

1) Fix a refcount leak in vti6.
   From Nicolas Dichtel.

2) Fix a wrong if statement in xfrm_sk_policy_lookup.
   From Florian Westphal.

3) The flowcache watermarks are per cpu. Take this into
   account when comparing to the threshold where we
   refusing new allocations. From Miroslav Urbanek.

Please pull or let me know if there are problems.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/flow.c
net/ipv6/ip6_vti.c
net/xfrm/xfrm_policy.c

index 3937b1b68d5bc7ad50691716ac1612332a5dc997..18e8893d4be59905ba1053fffea7cc16d0e054af 100644 (file)
@@ -95,7 +95,6 @@ static void flow_cache_gc_task(struct work_struct *work)
        list_for_each_entry_safe(fce, n, &gc_list, u.gc_list) {
                flow_entry_kill(fce, xfrm);
                atomic_dec(&xfrm->flow_cache_gc_count);
-               WARN_ON(atomic_read(&xfrm->flow_cache_gc_count) < 0);
        }
 }
 
@@ -236,9 +235,8 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
                if (fcp->hash_count > fc->high_watermark)
                        flow_cache_shrink(fc, fcp);
 
-               if (fcp->hash_count > 2 * fc->high_watermark ||
-                   atomic_read(&net->xfrm.flow_cache_gc_count) > fc->high_watermark) {
-                       atomic_inc(&net->xfrm.flow_cache_genid);
+               if (atomic_read(&net->xfrm.flow_cache_gc_count) >
+                   2 * num_online_cpus() * fc->high_watermark) {
                        flo = ERR_PTR(-ENOBUFS);
                        goto ret_object;
                }
index 8a02ca8a11af4b388bfe996711458efd46b641cf..c299c1e2bbf06ed31bc9fd30c7c96111fe606fc5 100644 (file)
@@ -1138,6 +1138,33 @@ static struct xfrm6_protocol vti_ipcomp6_protocol __read_mostly = {
        .priority       =       100,
 };
 
+static bool is_vti6_tunnel(const struct net_device *dev)
+{
+       return dev->netdev_ops == &vti6_netdev_ops;
+}
+
+static int vti6_device_event(struct notifier_block *unused,
+                            unsigned long event, void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct ip6_tnl *t = netdev_priv(dev);
+
+       if (!is_vti6_tunnel(dev))
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_DOWN:
+               if (!net_eq(t->net, dev_net(dev)))
+                       xfrm_garbage_collect(t->net);
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block vti6_notifier_block __read_mostly = {
+       .notifier_call = vti6_device_event,
+};
+
 /**
  * vti6_tunnel_init - register protocol and reserve needed resources
  *
@@ -1148,6 +1175,8 @@ static int __init vti6_tunnel_init(void)
        const char *msg;
        int err;
 
+       register_netdevice_notifier(&vti6_notifier_block);
+
        msg = "tunnel device";
        err = register_pernet_device(&vti6_net_ops);
        if (err < 0)
@@ -1180,6 +1209,7 @@ xfrm_proto_ah_failed:
 xfrm_proto_esp_failed:
        unregister_pernet_device(&vti6_net_ops);
 pernet_dev_failed:
+       unregister_netdevice_notifier(&vti6_notifier_block);
        pr_err("vti6 init: failed to register %s\n", msg);
        return err;
 }
@@ -1194,6 +1224,7 @@ static void __exit vti6_tunnel_cleanup(void)
        xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH);
        xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
        unregister_pernet_device(&vti6_net_ops);
+       unregister_netdevice_notifier(&vti6_notifier_block);
 }
 
 module_init(vti6_tunnel_init);
index fd6986634e6fe4dc77993854323d7558637b94bc..5bf7e1bfeac7aa26549cdcac42ddf7cda5a3ad88 100644 (file)
@@ -1268,12 +1268,14 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
                        err = security_xfrm_policy_lookup(pol->security,
                                                      fl->flowi_secid,
                                                      policy_to_flow_dir(dir));
-                       if (!err && !xfrm_pol_hold_rcu(pol))
-                               goto again;
-                       else if (err == -ESRCH)
+                       if (!err) {
+                               if (!xfrm_pol_hold_rcu(pol))
+                                       goto again;
+                       } else if (err == -ESRCH) {
                                pol = NULL;
-                       else
+                       } else {
                                pol = ERR_PTR(err);
+                       }
                } else
                        pol = NULL;
        }