netfilter: helper: avoid extra expectation iterations on unregister
authorFlorian Westphal <fw@strlen.de>
Sun, 15 May 2016 17:50:14 +0000 (19:50 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 7 Jun 2016 15:26:51 +0000 (17:26 +0200)
The expectation table is not duplicated per net namespace anymore, so we can move
the expectation table and conntrack table iteration out of the per-net loop.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_conntrack_helper.c

index f703adb7e5f7166ca47380aedd8ad0074e361ee4..7ba16e9c69fa2e84cad3a1cea8ed59e5931cae75 100644 (file)
@@ -388,13 +388,40 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
 
 static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
                                             struct net *net)
+{
+       struct nf_conntrack_tuple_hash *h;
+       const struct hlist_nulls_node *nn;
+       int cpu;
+
+       /* Get rid of expecteds, set helpers to NULL. */
+       for_each_possible_cpu(cpu) {
+               struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+               spin_lock_bh(&pcpu->lock);
+               hlist_nulls_for_each_entry(h, nn, &pcpu->unconfirmed, hnnode)
+                       unhelp(h, me);
+               spin_unlock_bh(&pcpu->lock);
+       }
+}
+
+void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
 {
        struct nf_conntrack_tuple_hash *h;
        struct nf_conntrack_expect *exp;
        const struct hlist_node *next;
        const struct hlist_nulls_node *nn;
+       struct net *net;
        unsigned int i;
-       int cpu;
+
+       mutex_lock(&nf_ct_helper_mutex);
+       hlist_del_rcu(&me->hnode);
+       nf_ct_helper_count--;
+       mutex_unlock(&nf_ct_helper_mutex);
+
+       /* Make sure every nothing is still using the helper unless its a
+        * connection in the hash.
+        */
+       synchronize_rcu();
 
        /* Get rid of expectations */
        spin_lock_bh(&nf_conntrack_expect_lock);
@@ -414,15 +441,11 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
        }
        spin_unlock_bh(&nf_conntrack_expect_lock);
 
-       /* Get rid of expecteds, set helpers to NULL. */
-       for_each_possible_cpu(cpu) {
-               struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+       rtnl_lock();
+       for_each_net(net)
+               __nf_conntrack_helper_unregister(me, net);
+       rtnl_unlock();
 
-               spin_lock_bh(&pcpu->lock);
-               hlist_nulls_for_each_entry(h, nn, &pcpu->unconfirmed, hnnode)
-                       unhelp(h, me);
-               spin_unlock_bh(&pcpu->lock);
-       }
        local_bh_disable();
        for (i = 0; i < nf_conntrack_htable_size; i++) {
                nf_conntrack_lock(&nf_conntrack_locks[i % CONNTRACK_LOCKS]);
@@ -434,26 +457,6 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
        }
        local_bh_enable();
 }
-
-void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
-{
-       struct net *net;
-
-       mutex_lock(&nf_ct_helper_mutex);
-       hlist_del_rcu(&me->hnode);
-       nf_ct_helper_count--;
-       mutex_unlock(&nf_ct_helper_mutex);
-
-       /* Make sure every nothing is still using the helper unless its a
-        * connection in the hash.
-        */
-       synchronize_rcu();
-
-       rtnl_lock();
-       for_each_net(net)
-               __nf_conntrack_helper_unregister(me, net);
-       rtnl_unlock();
-}
 EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
 
 static struct nf_ct_ext_type helper_extend __read_mostly = {