u_int8_t af;            /* address/protocol family */
        int priority;           /* hook order */
 
-       /* called when table is needed in the given netns */
-       int (*table_init)(struct net *net);
-
        /* A unique name... */
        const char name[XT_TABLE_MAXNAMELEN];
 };
 
 struct nf_hook_ops *xt_hook_ops_alloc(const struct xt_table *, nf_hookfn *);
 
+int xt_register_template(const struct xt_table *t, int(*table_init)(struct net *net));
+void xt_unregister_template(const struct xt_table *t);
+
 #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
 #include <net/compat.h>
 
 
 #define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \
                           (1 << NF_ARP_FORWARD))
 
-static int __net_init arptable_filter_table_init(struct net *net);
-
 static const struct xt_table packet_filter = {
        .name           = "filter",
        .valid_hooks    = FILTER_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_ARP,
        .priority       = NF_IP_PRI_FILTER,
-       .table_init     = arptable_filter_table_init,
 };
 
 /* The work comes in here from netfilter.c */
 
 static struct nf_hook_ops *arpfilter_ops __read_mostly;
 
-static int __net_init arptable_filter_table_init(struct net *net)
+static int arptable_filter_table_init(struct net *net)
 {
        struct arpt_replace *repl;
        int err;
 
 static int __init arptable_filter_init(void)
 {
-       int ret;
+       int ret = xt_register_template(&packet_filter,
+                                      arptable_filter_table_init);
+
+       if (ret < 0)
+               return ret;
 
        arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arptable_filter_hook);
-       if (IS_ERR(arpfilter_ops))
+       if (IS_ERR(arpfilter_ops)) {
+               xt_unregister_template(&packet_filter);
                return PTR_ERR(arpfilter_ops);
+       }
 
        ret = register_pernet_subsys(&arptable_filter_net_ops);
        if (ret < 0) {
+               xt_unregister_template(&packet_filter);
                kfree(arpfilter_ops);
                return ret;
        }
 
-       ret = arptable_filter_table_init(&init_net);
-       if (ret) {
-               unregister_pernet_subsys(&arptable_filter_net_ops);
-               kfree(arpfilter_ops);
-       }
-
        return ret;
 }
 
 static void __exit arptable_filter_fini(void)
 {
        unregister_pernet_subsys(&arptable_filter_net_ops);
+       xt_unregister_template(&packet_filter);
        kfree(arpfilter_ops);
 }
 
 
 #define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \
                            (1 << NF_INET_FORWARD) | \
                            (1 << NF_INET_LOCAL_OUT))
-static int __net_init iptable_filter_table_init(struct net *net);
 
 static const struct xt_table packet_filter = {
        .name           = "filter",
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV4,
        .priority       = NF_IP_PRI_FILTER,
-       .table_init     = iptable_filter_table_init,
 };
 
 static unsigned int
 static bool forward __read_mostly = true;
 module_param(forward, bool, 0000);
 
-static int __net_init iptable_filter_table_init(struct net *net)
+static int iptable_filter_table_init(struct net *net)
 {
        struct ipt_replace *repl;
        int err;
 
 static int __net_init iptable_filter_net_init(struct net *net)
 {
-       if (net == &init_net || !forward)
+       if (!forward)
                return iptable_filter_table_init(net);
 
        return 0;
 
 static int __init iptable_filter_init(void)
 {
-       int ret;
+       int ret = xt_register_template(&packet_filter,
+                                      iptable_filter_table_init);
+
+       if (ret < 0)
+               return ret;
 
        filter_ops = xt_hook_ops_alloc(&packet_filter, iptable_filter_hook);
-       if (IS_ERR(filter_ops))
+       if (IS_ERR(filter_ops)) {
+               xt_unregister_template(&packet_filter);
                return PTR_ERR(filter_ops);
+       }
 
        ret = register_pernet_subsys(&iptable_filter_net_ops);
-       if (ret < 0)
+       if (ret < 0) {
+               xt_unregister_template(&packet_filter);
                kfree(filter_ops);
+               return ret;
+       }
 
-       return ret;
+       return 0;
 }
 
 static void __exit iptable_filter_fini(void)
 {
        unregister_pernet_subsys(&iptable_filter_net_ops);
+       xt_unregister_template(&packet_filter);
        kfree(filter_ops);
 }
 
 
                            (1 << NF_INET_LOCAL_OUT) | \
                            (1 << NF_INET_POST_ROUTING))
 
-static int __net_init iptable_mangle_table_init(struct net *net);
-
 static const struct xt_table packet_mangler = {
        .name           = "mangle",
        .valid_hooks    = MANGLE_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV4,
        .priority       = NF_IP_PRI_MANGLE,
-       .table_init     = iptable_mangle_table_init,
 };
 
 static unsigned int
 }
 
 static struct nf_hook_ops *mangle_ops __read_mostly;
-static int __net_init iptable_mangle_table_init(struct net *net)
+static int iptable_mangle_table_init(struct net *net)
 {
        struct ipt_replace *repl;
        int ret;
 
 static int __init iptable_mangle_init(void)
 {
-       int ret;
+       int ret = xt_register_template(&packet_mangler,
+                                      iptable_mangle_table_init);
 
        mangle_ops = xt_hook_ops_alloc(&packet_mangler, iptable_mangle_hook);
        if (IS_ERR(mangle_ops)) {
+               xt_unregister_template(&packet_mangler);
                ret = PTR_ERR(mangle_ops);
                return ret;
        }
 
        ret = register_pernet_subsys(&iptable_mangle_net_ops);
        if (ret < 0) {
+               xt_unregister_template(&packet_mangler);
                kfree(mangle_ops);
                return ret;
        }
 
-       ret = iptable_mangle_table_init(&init_net);
-       if (ret) {
-               unregister_pernet_subsys(&iptable_mangle_net_ops);
-               kfree(mangle_ops);
-       }
-
        return ret;
 }
 
 static void __exit iptable_mangle_fini(void)
 {
        unregister_pernet_subsys(&iptable_mangle_net_ops);
+       xt_unregister_template(&packet_mangler);
        kfree(mangle_ops);
 }
 
 
        struct nf_hook_ops *nf_nat_ops;
 };
 
-static int __net_init iptable_nat_table_init(struct net *net);
-
 static unsigned int iptable_nat_net_id __read_mostly;
 
 static const struct xt_table nf_nat_ipv4_table = {
                          (1 << NF_INET_LOCAL_IN),
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV4,
-       .table_init     = iptable_nat_table_init,
 };
 
 static unsigned int iptable_nat_do_chain(void *priv,
        kfree(ops);
 }
 
-static int __net_init iptable_nat_table_init(struct net *net)
+static int iptable_nat_table_init(struct net *net)
 {
        struct ipt_replace *repl;
        int ret;
 
 static int __init iptable_nat_init(void)
 {
-       int ret = register_pernet_subsys(&iptable_nat_net_ops);
+       int ret = xt_register_template(&nf_nat_ipv4_table,
+                                      iptable_nat_table_init);
+
+       if (ret < 0)
+               return ret;
 
-       if (ret)
+       ret = register_pernet_subsys(&iptable_nat_net_ops);
+       if (ret < 0) {
+               xt_unregister_template(&nf_nat_ipv4_table);
                return ret;
+       }
 
-       ret = iptable_nat_table_init(&init_net);
-       if (ret)
-               unregister_pernet_subsys(&iptable_nat_net_ops);
        return ret;
 }
 
 static void __exit iptable_nat_exit(void)
 {
        unregister_pernet_subsys(&iptable_nat_net_ops);
+       xt_unregister_template(&nf_nat_ipv4_table);
 }
 
 module_init(iptable_nat_init);
 
 
 #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT))
 
-static int __net_init iptable_raw_table_init(struct net *net);
-
 static bool raw_before_defrag __read_mostly;
 MODULE_PARM_DESC(raw_before_defrag, "Enable raw table before defrag");
 module_param(raw_before_defrag, bool, 0000);
        .me = THIS_MODULE,
        .af = NFPROTO_IPV4,
        .priority = NF_IP_PRI_RAW,
-       .table_init = iptable_raw_table_init,
 };
 
 static const struct xt_table packet_raw_before_defrag = {
        .me = THIS_MODULE,
        .af = NFPROTO_IPV4,
        .priority = NF_IP_PRI_RAW_BEFORE_DEFRAG,
-       .table_init = iptable_raw_table_init,
 };
 
 /* The work comes in here from netfilter.c. */
                pr_info("Enabling raw table before defrag\n");
        }
 
+       ret = xt_register_template(table,
+                                  iptable_raw_table_init);
+       if (ret < 0)
+               return ret;
+
        rawtable_ops = xt_hook_ops_alloc(table, iptable_raw_hook);
-       if (IS_ERR(rawtable_ops))
+       if (IS_ERR(rawtable_ops)) {
+               xt_unregister_template(table);
                return PTR_ERR(rawtable_ops);
+       }
 
        ret = register_pernet_subsys(&iptable_raw_net_ops);
        if (ret < 0) {
+               xt_unregister_template(table);
                kfree(rawtable_ops);
                return ret;
        }
 
-       ret = iptable_raw_table_init(&init_net);
-       if (ret) {
-               unregister_pernet_subsys(&iptable_raw_net_ops);
-               kfree(rawtable_ops);
-       }
-
        return ret;
 }
 
 {
        unregister_pernet_subsys(&iptable_raw_net_ops);
        kfree(rawtable_ops);
+       xt_unregister_template(&packet_raw);
 }
 
 module_init(iptable_raw_init);
 
                                (1 << NF_INET_FORWARD) | \
                                (1 << NF_INET_LOCAL_OUT)
 
-static int __net_init iptable_security_table_init(struct net *net);
-
 static const struct xt_table security_table = {
        .name           = "security",
        .valid_hooks    = SECURITY_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV4,
        .priority       = NF_IP_PRI_SECURITY,
-       .table_init     = iptable_security_table_init,
 };
 
 static unsigned int
 
 static struct nf_hook_ops *sectbl_ops __read_mostly;
 
-static int __net_init iptable_security_table_init(struct net *net)
+static int iptable_security_table_init(struct net *net)
 {
        struct ipt_replace *repl;
        int ret;
 
 static int __init iptable_security_init(void)
 {
-       int ret;
+       int ret = xt_register_template(&security_table,
+                                      iptable_security_table_init);
+
+       if (ret < 0)
+               return ret;
 
        sectbl_ops = xt_hook_ops_alloc(&security_table, iptable_security_hook);
-       if (IS_ERR(sectbl_ops))
+       if (IS_ERR(sectbl_ops)) {
+               xt_unregister_template(&security_table);
                return PTR_ERR(sectbl_ops);
+       }
 
        ret = register_pernet_subsys(&iptable_security_net_ops);
        if (ret < 0) {
+               xt_unregister_template(&security_table);
                kfree(sectbl_ops);
                return ret;
        }
 
-       ret = iptable_security_table_init(&init_net);
-       if (ret) {
-               unregister_pernet_subsys(&iptable_security_net_ops);
-               kfree(sectbl_ops);
-       }
-
        return ret;
 }
 
 {
        unregister_pernet_subsys(&iptable_security_net_ops);
        kfree(sectbl_ops);
+       xt_unregister_template(&security_table);
 }
 
 module_init(iptable_security_init);
 
                            (1 << NF_INET_FORWARD) | \
                            (1 << NF_INET_LOCAL_OUT))
 
-static int __net_init ip6table_filter_table_init(struct net *net);
-
 static const struct xt_table packet_filter = {
        .name           = "filter",
        .valid_hooks    = FILTER_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV6,
        .priority       = NF_IP6_PRI_FILTER,
-       .table_init     = ip6table_filter_table_init,
 };
 
 /* The work comes in here from netfilter.c. */
 static bool forward = true;
 module_param(forward, bool, 0000);
 
-static int __net_init ip6table_filter_table_init(struct net *net)
+static int ip6table_filter_table_init(struct net *net)
 {
        struct ip6t_replace *repl;
        int err;
 
 static int __net_init ip6table_filter_net_init(struct net *net)
 {
-       if (net == &init_net || !forward)
+       if (!forward)
                return ip6table_filter_table_init(net);
 
        return 0;
 
 static int __init ip6table_filter_init(void)
 {
-       int ret;
+       int ret = xt_register_template(&packet_filter,
+                                       ip6table_filter_table_init);
+
+       if (ret < 0)
+               return ret;
 
        filter_ops = xt_hook_ops_alloc(&packet_filter, ip6table_filter_hook);
-       if (IS_ERR(filter_ops))
+       if (IS_ERR(filter_ops)) {
+               xt_unregister_template(&packet_filter);
                return PTR_ERR(filter_ops);
+       }
 
        ret = register_pernet_subsys(&ip6table_filter_net_ops);
-       if (ret < 0)
+       if (ret < 0) {
+               xt_unregister_template(&packet_filter);
                kfree(filter_ops);
+               return ret;
+       }
 
        return ret;
 }
 static void __exit ip6table_filter_fini(void)
 {
        unregister_pernet_subsys(&ip6table_filter_net_ops);
+       xt_unregister_template(&packet_filter);
        kfree(filter_ops);
 }
 
 
                            (1 << NF_INET_LOCAL_OUT) | \
                            (1 << NF_INET_POST_ROUTING))
 
-static int __net_init ip6table_mangle_table_init(struct net *net);
-
 static const struct xt_table packet_mangler = {
        .name           = "mangle",
        .valid_hooks    = MANGLE_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV6,
        .priority       = NF_IP6_PRI_MANGLE,
-       .table_init     = ip6table_mangle_table_init,
 };
 
 static unsigned int
 }
 
 static struct nf_hook_ops *mangle_ops __read_mostly;
-static int __net_init ip6table_mangle_table_init(struct net *net)
+static int ip6table_mangle_table_init(struct net *net)
 {
        struct ip6t_replace *repl;
        int ret;
 
 static int __init ip6table_mangle_init(void)
 {
-       int ret;
+       int ret = xt_register_template(&packet_mangler,
+                                      ip6table_mangle_table_init);
+
+       if (ret < 0)
+               return ret;
 
        mangle_ops = xt_hook_ops_alloc(&packet_mangler, ip6table_mangle_hook);
-       if (IS_ERR(mangle_ops))
+       if (IS_ERR(mangle_ops)) {
+               xt_unregister_template(&packet_mangler);
                return PTR_ERR(mangle_ops);
+       }
 
        ret = register_pernet_subsys(&ip6table_mangle_net_ops);
        if (ret < 0) {
+               xt_unregister_template(&packet_mangler);
                kfree(mangle_ops);
                return ret;
        }
 
-       ret = ip6table_mangle_table_init(&init_net);
-       if (ret) {
-               unregister_pernet_subsys(&ip6table_mangle_net_ops);
-               kfree(mangle_ops);
-       }
        return ret;
 }
 
 static void __exit ip6table_mangle_fini(void)
 {
        unregister_pernet_subsys(&ip6table_mangle_net_ops);
+       xt_unregister_template(&packet_mangler);
        kfree(mangle_ops);
 }
 
 
        struct nf_hook_ops *nf_nat_ops;
 };
 
-static int __net_init ip6table_nat_table_init(struct net *net);
-
 static unsigned int ip6table_nat_net_id __read_mostly;
 
 static const struct xt_table nf_nat_ipv6_table = {
                          (1 << NF_INET_LOCAL_IN),
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV6,
-       .table_init     = ip6table_nat_table_init,
 };
 
 static unsigned int ip6table_nat_do_chain(void *priv,
        kfree(ops);
 }
 
-static int __net_init ip6table_nat_table_init(struct net *net)
+static int ip6table_nat_table_init(struct net *net)
 {
        struct ip6t_replace *repl;
        int ret;
 
 static int __init ip6table_nat_init(void)
 {
-       int ret = register_pernet_subsys(&ip6table_nat_net_ops);
+       int ret = xt_register_template(&nf_nat_ipv6_table,
+                                      ip6table_nat_table_init);
 
-       if (ret)
+       if (ret < 0)
                return ret;
 
-       ret = ip6table_nat_table_init(&init_net);
+       ret = register_pernet_subsys(&ip6table_nat_net_ops);
        if (ret)
-               unregister_pernet_subsys(&ip6table_nat_net_ops);
+               xt_unregister_template(&nf_nat_ipv6_table);
+
        return ret;
 }
 
 static void __exit ip6table_nat_exit(void)
 {
        unregister_pernet_subsys(&ip6table_nat_net_ops);
+       xt_unregister_template(&nf_nat_ipv6_table);
 }
 
 module_init(ip6table_nat_init);
 
 
 #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT))
 
-static int __net_init ip6table_raw_table_init(struct net *net);
-
 static bool raw_before_defrag __read_mostly;
 MODULE_PARM_DESC(raw_before_defrag, "Enable raw table before defrag");
 module_param(raw_before_defrag, bool, 0000);
        .me = THIS_MODULE,
        .af = NFPROTO_IPV6,
        .priority = NF_IP6_PRI_RAW,
-       .table_init = ip6table_raw_table_init,
 };
 
 static const struct xt_table packet_raw_before_defrag = {
        .me = THIS_MODULE,
        .af = NFPROTO_IPV6,
        .priority = NF_IP6_PRI_RAW_BEFORE_DEFRAG,
-       .table_init = ip6table_raw_table_init,
 };
 
 /* The work comes in here from netfilter.c. */
 
 static struct nf_hook_ops *rawtable_ops __read_mostly;
 
-static int __net_init ip6table_raw_table_init(struct net *net)
+static int ip6table_raw_table_init(struct net *net)
 {
        struct ip6t_replace *repl;
        const struct xt_table *table = &packet_raw;
 
 static int __init ip6table_raw_init(void)
 {
-       int ret;
        const struct xt_table *table = &packet_raw;
+       int ret;
 
        if (raw_before_defrag) {
                table = &packet_raw_before_defrag;
-
                pr_info("Enabling raw table before defrag\n");
        }
 
+       ret = xt_register_template(table, ip6table_raw_table_init);
+       if (ret < 0)
+               return ret;
+
        /* Register hooks */
        rawtable_ops = xt_hook_ops_alloc(table, ip6table_raw_hook);
-       if (IS_ERR(rawtable_ops))
+       if (IS_ERR(rawtable_ops)) {
+               xt_unregister_template(table);
                return PTR_ERR(rawtable_ops);
+       }
 
        ret = register_pernet_subsys(&ip6table_raw_net_ops);
        if (ret < 0) {
                kfree(rawtable_ops);
+               xt_unregister_template(table);
                return ret;
        }
 
-       ret = ip6table_raw_table_init(&init_net);
-       if (ret) {
-               unregister_pernet_subsys(&ip6table_raw_net_ops);
-               kfree(rawtable_ops);
-       }
        return ret;
 }
 
 static void __exit ip6table_raw_fini(void)
 {
        unregister_pernet_subsys(&ip6table_raw_net_ops);
+       xt_unregister_template(&packet_raw);
        kfree(rawtable_ops);
 }
 
 
                                (1 << NF_INET_FORWARD) | \
                                (1 << NF_INET_LOCAL_OUT)
 
-static int __net_init ip6table_security_table_init(struct net *net);
-
 static const struct xt_table security_table = {
        .name           = "security",
        .valid_hooks    = SECURITY_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV6,
        .priority       = NF_IP6_PRI_SECURITY,
-       .table_init     = ip6table_security_table_init,
 };
 
 static unsigned int
 
 static struct nf_hook_ops *sectbl_ops __read_mostly;
 
-static int __net_init ip6table_security_table_init(struct net *net)
+static int ip6table_security_table_init(struct net *net)
 {
        struct ip6t_replace *repl;
        int ret;
 
 static int __init ip6table_security_init(void)
 {
-       int ret;
+       int ret = xt_register_template(&security_table,
+                                      ip6table_security_table_init);
+
+       if (ret < 0)
+               return ret;
 
        sectbl_ops = xt_hook_ops_alloc(&security_table, ip6table_security_hook);
-       if (IS_ERR(sectbl_ops))
+       if (IS_ERR(sectbl_ops)) {
+               xt_unregister_template(&security_table);
                return PTR_ERR(sectbl_ops);
+       }
 
        ret = register_pernet_subsys(&ip6table_security_net_ops);
        if (ret < 0) {
                kfree(sectbl_ops);
+               xt_unregister_template(&security_table);
                return ret;
        }
 
-       ret = ip6table_security_table_init(&init_net);
-       if (ret) {
-               unregister_pernet_subsys(&ip6table_security_net_ops);
-               kfree(sectbl_ops);
-       }
        return ret;
 }
 
 static void __exit ip6table_security_fini(void)
 {
        unregister_pernet_subsys(&ip6table_security_net_ops);
+       xt_unregister_template(&security_table);
        kfree(sectbl_ops);
 }
 
 
 #define XT_PCPU_BLOCK_SIZE 4096
 #define XT_MAX_TABLE_SIZE      (512 * 1024 * 1024)
 
+struct xt_template {
+       struct list_head list;
+
+       /* called when table is needed in the given netns */
+       int (*table_init)(struct net *net);
+
+       struct module *me;
+
+       /* A unique name... */
+       char name[XT_TABLE_MAXNAMELEN];
+};
+
+static struct list_head xt_templates[NFPROTO_NUMPROTO];
+
 struct xt_pernet {
        struct list_head tables[NFPROTO_NUMPROTO];
 };
                                    const char *name)
 {
        struct xt_pernet *xt_net = net_generic(net, xt_pernet_id);
-       struct xt_table *t, *found = NULL;
+       struct module *owner = NULL;
+       struct xt_template *tmpl;
+       struct xt_table *t;
 
        mutex_lock(&xt[af].mutex);
        list_for_each_entry(t, &xt_net->tables[af], list)
                if (strcmp(t->name, name) == 0 && try_module_get(t->me))
                        return t;
 
-       if (net == &init_net)
-               goto out;
-
-       /* Table doesn't exist in this netns, re-try init */
-       xt_net = net_generic(&init_net, xt_pernet_id);
-       list_for_each_entry(t, &xt_net->tables[af], list) {
+       /* Table doesn't exist in this netns, check larval list */
+       list_for_each_entry(tmpl, &xt_templates[af], list) {
                int err;
 
-               if (strcmp(t->name, name))
+               if (strcmp(tmpl->name, name))
                        continue;
-               if (!try_module_get(t->me))
+               if (!try_module_get(tmpl->me))
                        goto out;
+
+               owner = tmpl->me;
+
                mutex_unlock(&xt[af].mutex);
-               err = t->table_init(net);
+               err = tmpl->table_init(net);
                if (err < 0) {
-                       module_put(t->me);
+                       module_put(owner);
                        return ERR_PTR(err);
                }
 
-               found = t;
-
                mutex_lock(&xt[af].mutex);
                break;
        }
 
-       if (!found)
-               goto out;
-
-       xt_net = net_generic(net, xt_pernet_id);
        /* and once again: */
        list_for_each_entry(t, &xt_net->tables[af], list)
                if (strcmp(t->name, name) == 0)
                        return t;
 
-       module_put(found->me);
+       module_put(owner);
  out:
        mutex_unlock(&xt[af].mutex);
        return ERR_PTR(-ENOENT);
 }
 EXPORT_SYMBOL_GPL(xt_hook_ops_alloc);
 
+int xt_register_template(const struct xt_table *table,
+                        int (*table_init)(struct net *net))
+{
+       int ret = -EEXIST, af = table->af;
+       struct xt_template *t;
+
+       mutex_lock(&xt[af].mutex);
+
+       list_for_each_entry(t, &xt_templates[af], list) {
+               if (WARN_ON_ONCE(strcmp(table->name, t->name) == 0))
+                       goto out_unlock;
+       }
+
+       ret = -ENOMEM;
+       t = kzalloc(sizeof(*t), GFP_KERNEL);
+       if (!t)
+               goto out_unlock;
+
+       BUILD_BUG_ON(sizeof(t->name) != sizeof(table->name));
+
+       strscpy(t->name, table->name, sizeof(t->name));
+       t->table_init = table_init;
+       t->me = table->me;
+       list_add(&t->list, &xt_templates[af]);
+       ret = 0;
+out_unlock:
+       mutex_unlock(&xt[af].mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xt_register_template);
+
+void xt_unregister_template(const struct xt_table *table)
+{
+       struct xt_template *t;
+       int af = table->af;
+
+       mutex_lock(&xt[af].mutex);
+       list_for_each_entry(t, &xt_templates[af], list) {
+               if (strcmp(table->name, t->name))
+                       continue;
+
+               list_del(&t->list);
+               mutex_unlock(&xt[af].mutex);
+               kfree(t);
+               return;
+       }
+
+       mutex_unlock(&xt[af].mutex);
+       WARN_ON_ONCE(1);
+}
+EXPORT_SYMBOL_GPL(xt_unregister_template);
+
 int xt_proto_init(struct net *net, u_int8_t af)
 {
 #ifdef CONFIG_PROC_FS
 #endif
                INIT_LIST_HEAD(&xt[i].target);
                INIT_LIST_HEAD(&xt[i].match);
+               INIT_LIST_HEAD(&xt_templates[i]);
        }
        rv = register_pernet_subsys(&xt_net_ops);
        if (rv < 0)