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,
 
        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;
 
        while (untrack_refs() > 0)
                schedule();
 
-       nf_conntrack_proto_fini();
 #ifdef CONFIG_NF_CONNTRACK_ZONES
        nf_ct_extend_unregister(&nf_ct_zone_extend);
 #endif
           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)) {
        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)
 
 #ifdef CONFIG_NF_CONNTRACK_ZONES
 err_extend:
-       nf_conntrack_proto_fini();
 #endif
-err_proto:
        return ret;
 }
 
        ret = nf_conntrack_helper_init(net);
        if (ret < 0)
                goto err_helper;
-
        return 0;
-
 err_helper:
        nf_conntrack_timeout_fini(net);
 err_timeout:
                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;
        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:
 
 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
 }
 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]);
+       }
 }
 
 
 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)
 
 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. */
 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,
 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,
 #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,
        .ctl_compat_table       = generic_compat_sysctl_table,
 #endif
 #endif
+       .init_net               = generic_init_net,
 };