netfilter: nf_ct_generic: add namespace support
authorGao feng <gaofeng@cn.fujitsu.com>
Mon, 28 May 2012 21:04:11 +0000 (21:04 +0000)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 7 Jun 2012 12:58:39 +0000 (14:58 +0200)
This patch adds namespace support for the generic layer 4 protocol
tracker.

Acked-by: Eric W. Biederman <ebiederm@xmission.com>
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
include/net/netns/conntrack.h
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_proto.c
net/netfilter/nf_conntrack_proto_generic.c

index aced085132e7e52591f05ba1f1529dbba420465b..d8f5b9f5216939d2053c8c99ad54925fb5a0ce5c 100644 (file)
@@ -28,8 +28,8 @@ extern unsigned int nf_conntrack_in(struct net *net,
 extern int nf_conntrack_init(struct net *net);
 extern void nf_conntrack_cleanup(struct net *net);
 
-extern int nf_conntrack_proto_init(void);
-extern void nf_conntrack_proto_fini(void);
+extern int nf_conntrack_proto_init(struct net *net);
+extern void nf_conntrack_proto_fini(struct net *net);
 
 extern bool
 nf_ct_get_tuple(const struct sk_buff *skb,
index b2dbcc5cd81355d6d294d53e672829ebd6e9553c..0ef8592d48bfc2deec7d5bb526989d31ff3e17e0 100644 (file)
@@ -20,7 +20,13 @@ struct nf_proto_net {
        unsigned int            users;
 };
 
+struct nf_generic_net {
+       struct nf_proto_net pn;
+       unsigned int timeout;
+};
+
 struct nf_ip_net {
+       struct nf_generic_net   generic;
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
        struct ctl_table_header *ctl_table_header;
        struct ctl_table        *ctl_table;
index ac3af97cc468eded7991ca98cd9dd6cec7f4d1cb..068f2e0ec58e1b53a2dd2b067bc1b1b403b745fb 100644 (file)
@@ -1333,7 +1333,6 @@ static void nf_conntrack_cleanup_init_net(void)
        while (untrack_refs() > 0)
                schedule();
 
-       nf_conntrack_proto_fini();
 #ifdef CONFIG_NF_CONNTRACK_ZONES
        nf_ct_extend_unregister(&nf_ct_zone_extend);
 #endif
@@ -1372,7 +1371,7 @@ void nf_conntrack_cleanup(struct net *net)
           netfilter framework.  Roll on, two-stage module
           delete... */
        synchronize_net();
-
+       nf_conntrack_proto_fini(net);
        nf_conntrack_cleanup_net(net);
 
        if (net_eq(net, &init_net)) {
@@ -1496,11 +1495,6 @@ static int nf_conntrack_init_init_net(void)
        printk(KERN_INFO "nf_conntrack version %s (%u buckets, %d max)\n",
               NF_CONNTRACK_VERSION, nf_conntrack_htable_size,
               nf_conntrack_max);
-
-       ret = nf_conntrack_proto_init();
-       if (ret < 0)
-               goto err_proto;
-
 #ifdef CONFIG_NF_CONNTRACK_ZONES
        ret = nf_ct_extend_register(&nf_ct_zone_extend);
        if (ret < 0)
@@ -1518,9 +1512,7 @@ static int nf_conntrack_init_init_net(void)
 
 #ifdef CONFIG_NF_CONNTRACK_ZONES
 err_extend:
-       nf_conntrack_proto_fini();
 #endif
-err_proto:
        return ret;
 }
 
@@ -1583,9 +1575,7 @@ static int nf_conntrack_init_net(struct net *net)
        ret = nf_conntrack_helper_init(net);
        if (ret < 0)
                goto err_helper;
-
        return 0;
-
 err_helper:
        nf_conntrack_timeout_fini(net);
 err_timeout:
@@ -1622,6 +1612,9 @@ int nf_conntrack_init(struct net *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;
@@ -1637,6 +1630,8 @@ int nf_conntrack_init(struct net *net)
        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:
index a8daf0faadb71a9be1dd3b802bfcd72806f3c0d1..b095b4aefd7cfbe19da3493e7bc3956e408ec4a2 100644 (file)
@@ -302,10 +302,16 @@ EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
 static struct nf_proto_net *nf_ct_l4proto_net(struct net *net,
                                              struct nf_conntrack_l4proto *l4proto)
 {
-       if (l4proto->net_id)
-               return net_generic(net, *l4proto->net_id);
-       else
-               return NULL;
+       switch (l4proto->l4proto) {
+       case 255: /* l4proto_generic */
+               return (struct nf_proto_net *)&net->ct.nf_ct_proto.generic;
+       default:
+               if (l4proto->net_id)
+                       return net_generic(net, *l4proto->net_id);
+               else
+                       return NULL;
+       }
+       return NULL;
 }
 
 static
@@ -487,28 +493,34 @@ void nf_conntrack_l4proto_unregister(struct net *net,
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister);
 
-int nf_conntrack_proto_init(void)
+int nf_conntrack_proto_init(struct net *net)
 {
        unsigned int i;
        int err;
-
-       err = nf_ct_l4proto_register_sysctl(&init_net, &nf_conntrack_l4proto_generic);
+       err = nf_conntrack_l4proto_generic.init_net(net);
+       if (err < 0)
+               return err;
+       err = nf_ct_l4proto_register_sysctl(net,
+                                           &nf_conntrack_l4proto_generic);
        if (err < 0)
                return err;
 
-       for (i = 0; i < AF_MAX; i++)
-               rcu_assign_pointer(nf_ct_l3protos[i],
-                                  &nf_conntrack_l3proto_generic);
+       if (net == &init_net) {
+               for (i = 0; i < AF_MAX; i++)
+                       rcu_assign_pointer(nf_ct_l3protos[i],
+                                          &nf_conntrack_l3proto_generic);
+       }
        return 0;
 }
 
-void nf_conntrack_proto_fini(void)
+void nf_conntrack_proto_fini(struct net *net)
 {
        unsigned int i;
-
-       nf_ct_l4proto_unregister_sysctl(&init_net, &nf_conntrack_l4proto_generic);
-
-       /* free l3proto protocol tables */
-       for (i = 0; i < PF_MAX; i++)
-               kfree(nf_ct_protos[i]);
+       nf_ct_l4proto_unregister_sysctl(net,
+                                       &nf_conntrack_l4proto_generic);
+       if (net == &init_net) {
+               /* free l3proto protocol tables */
+               for (i = 0; i < PF_MAX; i++)
+                       kfree(nf_ct_protos[i]);
+       }
 }
index d8923d54b3585bf579c66eaba82dc4ec7d464236..19bc880eb4e2d0a988ddd7530a6f368a2a89b03a 100644 (file)
 
 static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ;
 
+static inline struct nf_generic_net *generic_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.generic;
+}
+
 static bool generic_pkt_to_tuple(const struct sk_buff *skb,
                                 unsigned int dataoff,
                                 struct nf_conntrack_tuple *tuple)
@@ -42,7 +47,7 @@ static int generic_print_tuple(struct seq_file *s,
 
 static unsigned int *generic_get_timeouts(struct net *net)
 {
-       return &nf_ct_generic_timeout;
+       return &(generic_pernet(net)->timeout);
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
@@ -110,7 +115,6 @@ static struct ctl_table_header *generic_sysctl_header;
 static struct ctl_table generic_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_generic_timeout",
-               .data           = &nf_ct_generic_timeout,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -121,7 +125,6 @@ static struct ctl_table generic_sysctl_table[] = {
 static struct ctl_table generic_compat_sysctl_table[] = {
        {
                .procname       = "ip_conntrack_generic_timeout",
-               .data           = &nf_ct_generic_timeout,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -131,6 +134,34 @@ static struct ctl_table generic_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
 
+static int generic_init_net(struct net *net)
+{
+       struct nf_generic_net *gn = generic_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)gn;
+       gn->timeout = nf_ct_generic_timeout;
+#ifdef CONFIG_SYSCTL
+       pn->ctl_table = kmemdup(generic_sysctl_table,
+                               sizeof(generic_sysctl_table),
+                               GFP_KERNEL);
+       if (!pn->ctl_table)
+               return -ENOMEM;
+       pn->ctl_table[0].data = &gn->timeout;
+
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       pn->ctl_compat_table = kmemdup(generic_compat_sysctl_table,
+                                      sizeof(generic_compat_sysctl_table),
+                                      GFP_KERNEL);
+       if (!pn->ctl_compat_table) {
+               kfree(pn->ctl_table);
+               pn->ctl_table = NULL;
+               return -ENOMEM;
+       }
+       pn->ctl_compat_table[0].data = &gn->timeout;
+#endif
+#endif
+       return 0;
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
 {
        .l3proto                = PF_UNSPEC,
@@ -158,4 +189,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
        .ctl_compat_table       = generic_compat_sysctl_table,
 #endif
 #endif
+       .init_net               = generic_init_net,
 };