netfilter: nf_conntrack: move initialization out of pernet operations
authorGao feng <gaofeng@cn.fujitsu.com>
Mon, 21 Jan 2013 22:10:24 +0000 (22:10 +0000)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 23 Jan 2013 11:53:35 +0000 (12:53 +0100)
nf_conntrack initialization and cleanup codes happens in pernet
operations function. This task should be done in module_init/exit.
We can't use init_net to identify if it's the right time to initialize
or cleanup since we cannot make assumption on the order netns are
created/destroyed.

Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nf_conntrack_core.h
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_standalone.c

index e98aeb3da033a38e29f745d5f043a33d3888bcc3..e05c1f67055c042dcf49b48175d8a4cf74fcae84 100644 (file)
@@ -25,12 +25,16 @@ extern unsigned int nf_conntrack_in(struct net *net,
                                    unsigned int hooknum,
                                    struct sk_buff *skb);
 
-extern int nf_conntrack_init(struct net *net);
-extern void nf_conntrack_cleanup(struct net *net);
+extern int nf_conntrack_init_net(struct net *net);
+extern void nf_conntrack_cleanup_net(struct net *net);
 
 extern int nf_conntrack_proto_init(struct net *net);
 extern void nf_conntrack_proto_fini(struct net *net);
 
+extern int nf_conntrack_init_start(void);
+extern void nf_conntrack_cleanup_start(void);
+
+extern void nf_conntrack_init_end(void);
 extern void nf_conntrack_cleanup_end(void);
 
 extern bool
index 85aa4b7149c5d6b63b3f3edc3d32d6c9930f20ef..fb3e514c461eca3fe16263572099df5886c4127a 100644 (file)
@@ -1334,8 +1334,14 @@ static int untrack_refs(void)
        return cnt;
 }
 
-static void nf_conntrack_cleanup_init_net(void)
+void nf_conntrack_cleanup_start(void)
 {
+       RCU_INIT_POINTER(ip_ct_attach, NULL);
+}
+
+void nf_conntrack_cleanup_end(void)
+{
+       RCU_INIT_POINTER(nf_ct_destroy, NULL);
        while (untrack_refs() > 0)
                schedule();
 
@@ -1344,8 +1350,18 @@ static void nf_conntrack_cleanup_init_net(void)
 #endif
 }
 
-static void nf_conntrack_cleanup_net(struct net *net)
+/*
+ * Mishearing the voices in his head, our hero wonders how he's
+ * supposed to kill the mall.
+ */
+void nf_conntrack_cleanup_net(struct net *net)
 {
+       /*
+        * This makes sure all current packets have passed through
+        *  netfilter framework.  Roll on, two-stage module
+        *  delete...
+        */
+       synchronize_net();
  i_see_dead_people:
        nf_ct_iterate_cleanup(net, kill_all, NULL);
        nf_ct_release_dying_list(net);
@@ -1355,6 +1371,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
        }
 
        nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
+       nf_conntrack_proto_fini(net);
        nf_conntrack_labels_fini(net);
        nf_conntrack_helper_fini(net);
        nf_conntrack_timeout_fini(net);
@@ -1367,27 +1384,6 @@ static void nf_conntrack_cleanup_net(struct net *net)
        free_percpu(net->ct.stat);
 }
 
-/* Mishearing the voices in his head, our hero wonders how he's
-   supposed to kill the mall. */
-void nf_conntrack_cleanup(struct net *net)
-{
-       if (net_eq(net, &init_net))
-               RCU_INIT_POINTER(ip_ct_attach, NULL);
-
-       /* This makes sure all current packets have passed through
-          netfilter framework.  Roll on, two-stage module
-          delete... */
-       synchronize_net();
-       nf_conntrack_proto_fini(net);
-       nf_conntrack_cleanup_net(net);
-}
-
-void nf_conntrack_cleanup_end(void)
-{
-       RCU_INIT_POINTER(nf_ct_destroy, NULL);
-       nf_conntrack_cleanup_init_net();
-}
-
 void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
 {
        struct hlist_nulls_head *hash;
@@ -1478,7 +1474,7 @@ void nf_ct_untracked_status_or(unsigned long bits)
 }
 EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or);
 
-static int nf_conntrack_init_init_net(void)
+int nf_conntrack_init_start(void)
 {
        int max_factor = 8;
        int ret, cpu;
@@ -1526,6 +1522,16 @@ err_extend:
        return ret;
 }
 
+void nf_conntrack_init_end(void)
+{
+       /* For use by REJECT target */
+       RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach);
+       RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack);
+
+       /* Howto get NAT offsets */
+       RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
+}
+
 /*
  * We need to use special "null" values, not used in hash table
  */
@@ -1533,7 +1539,7 @@ err_extend:
 #define DYING_NULLS_VAL                ((1<<30)+1)
 #define TEMPLATE_NULLS_VAL     ((1<<30)+2)
 
-static int nf_conntrack_init_net(struct net *net)
+int nf_conntrack_init_net(struct net *net)
 {
        int ret;
 
@@ -1592,8 +1598,13 @@ static int nf_conntrack_init_net(struct net *net)
        if (ret < 0)
                goto err_labels;
 
+       ret = nf_conntrack_proto_init(net);
+       if (ret < 0)
+               goto err_proto;
        return 0;
 
+err_proto:
+       nf_conntrack_labels_fini(net);
 err_labels:
        nf_conntrack_helper_fini(net);
 err_helper:
@@ -1622,38 +1633,3 @@ s16 (*nf_ct_nat_offset)(const struct nf_conn *ct,
                        enum ip_conntrack_dir dir,
                        u32 seq);
 EXPORT_SYMBOL_GPL(nf_ct_nat_offset);
-
-int nf_conntrack_init(struct net *net)
-{
-       int ret;
-
-       if (net_eq(net, &init_net)) {
-               ret = nf_conntrack_init_init_net();
-               if (ret < 0)
-                       goto out_init_net;
-       }
-       ret = nf_conntrack_proto_init(net);
-       if (ret < 0)
-               goto out_proto;
-       ret = nf_conntrack_init_net(net);
-       if (ret < 0)
-               goto out_net;
-
-       if (net_eq(net, &init_net)) {
-               /* For use by REJECT target */
-               RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach);
-               RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack);
-
-               /* Howto get NAT offsets */
-               RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
-       }
-       return 0;
-
-out_net:
-       nf_conntrack_proto_fini(net);
-out_proto:
-       if (net_eq(net, &init_net))
-               nf_conntrack_cleanup_init_net();
-out_init_net:
-       return ret;
-}
index e7185c68481659445b571ab5e7866728dd3947ec..725bf04a2fb92ba8800ea40242c0c43695f6d3e3 100644 (file)
@@ -472,13 +472,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
 {
        struct ctl_table *table;
 
-       if (net_eq(net, &init_net)) {
-               nf_ct_netfilter_header =
-                      register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
-               if (!nf_ct_netfilter_header)
-                       goto out;
-       }
-
        table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table),
                        GFP_KERNEL);
        if (!table)
@@ -502,10 +495,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
 out_unregister_netfilter:
        kfree(table);
 out_kmemdup:
-       if (net_eq(net, &init_net))
-               unregister_net_sysctl_table(nf_ct_netfilter_header);
-out:
-       printk(KERN_ERR "nf_conntrack: can't register to sysctl.\n");
        return -ENOMEM;
 }
 
@@ -513,8 +502,6 @@ static void nf_conntrack_standalone_fini_sysctl(struct net *net)
 {
        struct ctl_table *table;
 
-       if (net_eq(net, &init_net))
-               unregister_net_sysctl_table(nf_ct_netfilter_header);
        table = net->ct.sysctl_header->ctl_table_arg;
        unregister_net_sysctl_table(net->ct.sysctl_header);
        kfree(table);
@@ -530,51 +517,78 @@ static void nf_conntrack_standalone_fini_sysctl(struct net *net)
 }
 #endif /* CONFIG_SYSCTL */
 
-static int nf_conntrack_net_init(struct net *net)
+static int nf_conntrack_pernet_init(struct net *net)
 {
        int ret;
 
-       ret = nf_conntrack_init(net);
+       ret = nf_conntrack_init_net(net);
        if (ret < 0)
                goto out_init;
+
        ret = nf_conntrack_standalone_init_proc(net);
        if (ret < 0)
                goto out_proc;
+
        net->ct.sysctl_checksum = 1;
        net->ct.sysctl_log_invalid = 0;
        ret = nf_conntrack_standalone_init_sysctl(net);
        if (ret < 0)
                goto out_sysctl;
+
        return 0;
 
 out_sysctl:
        nf_conntrack_standalone_fini_proc(net);
 out_proc:
-       nf_conntrack_cleanup(net);
+       nf_conntrack_cleanup_net(net);
 out_init:
        return ret;
 }
 
-static void nf_conntrack_net_exit(struct net *net)
+static void nf_conntrack_pernet_exit(struct net *net)
 {
        nf_conntrack_standalone_fini_sysctl(net);
        nf_conntrack_standalone_fini_proc(net);
-       nf_conntrack_cleanup(net);
+       nf_conntrack_cleanup_net(net);
 }
 
 static struct pernet_operations nf_conntrack_net_ops = {
-       .init = nf_conntrack_net_init,
-       .exit = nf_conntrack_net_exit,
+       .init = nf_conntrack_pernet_init,
+       .exit = nf_conntrack_pernet_exit,
 };
 
 static int __init nf_conntrack_standalone_init(void)
 {
-       return register_pernet_subsys(&nf_conntrack_net_ops);
+       int ret = nf_conntrack_init_start();
+       if (ret < 0)
+               goto out_start;
+
+       nf_ct_netfilter_header =
+               register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
+       if (!nf_ct_netfilter_header)
+               goto out_sysctl;
+
+       ret = register_pernet_subsys(&nf_conntrack_net_ops);
+       if (ret < 0)
+               goto out_pernet;
+
+       nf_conntrack_init_end();
+       return 0;
+
+out_pernet:
+       unregister_net_sysctl_table(nf_ct_netfilter_header);
+out_sysctl:
+       pr_err("nf_conntrack: can't register to sysctl.\n");
+       nf_conntrack_cleanup_end();
+out_start:
+       return ret;
 }
 
 static void __exit nf_conntrack_standalone_fini(void)
 {
+       nf_conntrack_cleanup_start();
        unregister_pernet_subsys(&nf_conntrack_net_ops);
+       unregister_net_sysctl_table(nf_ct_netfilter_header);
        nf_conntrack_cleanup_end();
 }