unsigned int
 nf_nat_inet_fn(void *priv, struct sk_buff *skb,
-              const struct nf_hook_state *state,
-              unsigned int (*do_chain)(void *priv,
-                                       struct sk_buff *skb,
-                                       const struct nf_hook_state *state));
+              const struct nf_hook_state *state);
 
 int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family);
 
 
                                  enum ip_conntrack_info ctinfo,
                                  unsigned int hooknum);
 
-unsigned int nf_nat_ipv4_in(void *priv, struct sk_buff *skb,
-                           const struct nf_hook_state *state,
-                           unsigned int (*do_chain)(void *priv,
-                                                    struct sk_buff *skb,
-                                                    const struct nf_hook_state *state));
-
-unsigned int nf_nat_ipv4_out(void *priv, struct sk_buff *skb,
-                            const struct nf_hook_state *state,
-                            unsigned int (*do_chain)(void *priv,
-                                                     struct sk_buff *skb,
-                                                     const struct nf_hook_state *state));
-
-unsigned int nf_nat_ipv4_local_fn(void *priv,
-                                 struct sk_buff *skb,
-                                 const struct nf_hook_state *state,
-                                 unsigned int (*do_chain)(void *priv,
-                                                          struct sk_buff *skb,
-                                                          const struct nf_hook_state *state));
-
-unsigned int nf_nat_ipv4_fn(void *priv, struct sk_buff *skb,
-                           const struct nf_hook_state *state,
-                           unsigned int (*do_chain)(void *priv,
-                                                    struct sk_buff *skb,
-                                                    const struct nf_hook_state *state));
-
 int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, struct nf_conn *ct,
                                    enum ip_conntrack_info ctinfo,
                                    unsigned int hooknum, unsigned int hdrlen);
 
-unsigned int nf_nat_ipv6_in(void *priv, struct sk_buff *skb,
-                           const struct nf_hook_state *state,
-                           unsigned int (*do_chain)(void *priv,
-                                                    struct sk_buff *skb,
-                                                    const struct nf_hook_state *state));
-
-unsigned int nf_nat_ipv6_out(void *priv, struct sk_buff *skb,
-                            const struct nf_hook_state *state,
-                            unsigned int (*do_chain)(void *priv,
-                                                     struct sk_buff *skb,
-                                                     const struct nf_hook_state *state));
-
-unsigned int nf_nat_ipv6_local_fn(void *priv,
-                                 struct sk_buff *skb,
-                                 const struct nf_hook_state *state,
-                                 unsigned int (*do_chain)(void *priv,
-                                                          struct sk_buff *skb,
-                                                          const struct nf_hook_state *state));
+int nf_nat_l3proto_ipv4_register_fn(struct net *net, const struct nf_hook_ops *ops);
+void nf_nat_l3proto_ipv4_unregister_fn(struct net *net, const struct nf_hook_ops *ops);
 
-unsigned int nf_nat_ipv6_fn(void *priv, struct sk_buff *skb,
-                           const struct nf_hook_state *state,
-                           unsigned int (*do_chain)(void *priv,
-                                                    struct sk_buff *skb,
-                                                    const struct nf_hook_state *state));
+int nf_nat_l3proto_ipv6_register_fn(struct net *net, const struct nf_hook_ops *ops);
+void nf_nat_l3proto_ipv6_unregister_fn(struct net *net, const struct nf_hook_ops *ops);
 
 #endif /* _NF_NAT_L3PROTO_H */
 
        return ipt_do_table(skb, state, state->net->ipv4.nat_table);
 }
 
-static unsigned int iptable_nat_ipv4_fn(void *priv,
-                                       struct sk_buff *skb,
-                                       const struct nf_hook_state *state)
-{
-       return nf_nat_ipv4_fn(priv, skb, state, iptable_nat_do_chain);
-}
-
-static unsigned int iptable_nat_ipv4_in(void *priv,
-                                       struct sk_buff *skb,
-                                       const struct nf_hook_state *state)
-{
-       return nf_nat_ipv4_in(priv, skb, state, iptable_nat_do_chain);
-}
-
-static unsigned int iptable_nat_ipv4_out(void *priv,
-                                        struct sk_buff *skb,
-                                        const struct nf_hook_state *state)
-{
-       return nf_nat_ipv4_out(priv, skb, state, iptable_nat_do_chain);
-}
-
-static unsigned int iptable_nat_ipv4_local_fn(void *priv,
-                                             struct sk_buff *skb,
-                                             const struct nf_hook_state *state)
-{
-       return nf_nat_ipv4_local_fn(priv, skb, state, iptable_nat_do_chain);
-}
-
 static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
-       /* Before packet filtering, change destination */
        {
-               .hook           = iptable_nat_ipv4_in,
+               .hook           = iptable_nat_do_chain,
                .pf             = NFPROTO_IPV4,
-               .nat_hook       = true,
                .hooknum        = NF_INET_PRE_ROUTING,
                .priority       = NF_IP_PRI_NAT_DST,
        },
-       /* After packet filtering, change source */
        {
-               .hook           = iptable_nat_ipv4_out,
+               .hook           = iptable_nat_do_chain,
                .pf             = NFPROTO_IPV4,
-               .nat_hook       = true,
                .hooknum        = NF_INET_POST_ROUTING,
                .priority       = NF_IP_PRI_NAT_SRC,
        },
-       /* Before packet filtering, change destination */
        {
-               .hook           = iptable_nat_ipv4_local_fn,
+               .hook           = iptable_nat_do_chain,
                .pf             = NFPROTO_IPV4,
-               .nat_hook       = true,
                .hooknum        = NF_INET_LOCAL_OUT,
                .priority       = NF_IP_PRI_NAT_DST,
        },
-       /* After packet filtering, change source */
        {
-               .hook           = iptable_nat_ipv4_fn,
+               .hook           = iptable_nat_do_chain,
                .pf             = NFPROTO_IPV4,
-               .nat_hook       = true,
                .hooknum        = NF_INET_LOCAL_IN,
                .priority       = NF_IP_PRI_NAT_SRC,
        },
 };
 
+static int ipt_nat_register_lookups(struct net *net)
+{
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) {
+               ret = nf_nat_l3proto_ipv4_register_fn(net, &nf_nat_ipv4_ops[i]);
+               if (ret) {
+                       while (i)
+                               nf_nat_l3proto_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[--i]);
+
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void ipt_nat_unregister_lookups(struct net *net)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++)
+               nf_nat_l3proto_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[i]);
+}
+
 static int __net_init iptable_nat_table_init(struct net *net)
 {
        struct ipt_replace *repl;
        if (repl == NULL)
                return -ENOMEM;
        ret = ipt_register_table(net, &nf_nat_ipv4_table, repl,
-                                nf_nat_ipv4_ops, &net->ipv4.nat_table);
+                                NULL, &net->ipv4.nat_table);
+       if (ret < 0) {
+               kfree(repl);
+               return ret;
+       }
+
+       ret = ipt_nat_register_lookups(net);
+       if (ret < 0) {
+               ipt_unregister_table(net, net->ipv4.nat_table, NULL);
+               net->ipv4.nat_table = NULL;
+       }
+
        kfree(repl);
        return ret;
 }
 {
        if (!net->ipv4.nat_table)
                return;
-       ipt_unregister_table(net, net->ipv4.nat_table, nf_nat_ipv4_ops);
+       ipt_nat_unregister_lookups(net);
+       ipt_unregister_table(net, net->ipv4.nat_table, NULL);
        net->ipv4.nat_table = NULL;
 }
 
 
 }
 EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
 
-unsigned int
+static unsigned int
 nf_nat_ipv4_fn(void *priv, struct sk_buff *skb,
-              const struct nf_hook_state *state,
-              unsigned int (*do_chain)(void *priv,
-                                       struct sk_buff *skb,
-                                       const struct nf_hook_state *state))
+              const struct nf_hook_state *state)
 {
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
                }
        }
 
-       return nf_nat_inet_fn(priv, skb, state, do_chain);
+       return nf_nat_inet_fn(priv, skb, state);
 }
 EXPORT_SYMBOL_GPL(nf_nat_ipv4_fn);
 
-unsigned int
+static unsigned int
 nf_nat_ipv4_in(void *priv, struct sk_buff *skb,
-              const struct nf_hook_state *state,
-              unsigned int (*do_chain)(void *priv,
-                                        struct sk_buff *skb,
-                                        const struct nf_hook_state *state))
+              const struct nf_hook_state *state)
 {
        unsigned int ret;
        __be32 daddr = ip_hdr(skb)->daddr;
 
-       ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
+       ret = nf_nat_ipv4_fn(priv, skb, state);
        if (ret != NF_DROP && ret != NF_STOLEN &&
            daddr != ip_hdr(skb)->daddr)
                skb_dst_drop(skb);
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(nf_nat_ipv4_in);
 
-unsigned int
+static unsigned int
 nf_nat_ipv4_out(void *priv, struct sk_buff *skb,
-               const struct nf_hook_state *state,
-               unsigned int (*do_chain)(void *priv,
-                                         struct sk_buff *skb,
-                                         const struct nf_hook_state *state))
+               const struct nf_hook_state *state)
 {
 #ifdef CONFIG_XFRM
        const struct nf_conn *ct;
 #endif
        unsigned int ret;
 
-       ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
+       ret = nf_nat_ipv4_fn(priv, skb, state);
 #ifdef CONFIG_XFRM
        if (ret != NF_DROP && ret != NF_STOLEN &&
            !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
 #endif
        return ret;
 }
-EXPORT_SYMBOL_GPL(nf_nat_ipv4_out);
 
-unsigned int
+static unsigned int
 nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb,
-                    const struct nf_hook_state *state,
-                    unsigned int (*do_chain)(void *priv,
-                                              struct sk_buff *skb,
-                                              const struct nf_hook_state *state))
+                    const struct nf_hook_state *state)
 {
        const struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
        unsigned int ret;
        int err;
 
-       ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
+       ret = nf_nat_ipv4_fn(priv, skb, state);
        if (ret != NF_DROP && ret != NF_STOLEN &&
            (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
                enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
        }
        return ret;
 }
-EXPORT_SYMBOL_GPL(nf_nat_ipv4_local_fn);
+
+static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
+       /* Before packet filtering, change destination */
+       {
+               .hook           = nf_nat_ipv4_in,
+               .pf             = NFPROTO_IPV4,
+               .hooknum        = NF_INET_PRE_ROUTING,
+               .priority       = NF_IP_PRI_NAT_DST,
+       },
+       /* After packet filtering, change source */
+       {
+               .hook           = nf_nat_ipv4_out,
+               .pf             = NFPROTO_IPV4,
+               .hooknum        = NF_INET_POST_ROUTING,
+               .priority       = NF_IP_PRI_NAT_SRC,
+       },
+       /* Before packet filtering, change destination */
+       {
+               .hook           = nf_nat_ipv4_local_fn,
+               .pf             = NFPROTO_IPV4,
+               .hooknum        = NF_INET_LOCAL_OUT,
+               .priority       = NF_IP_PRI_NAT_DST,
+       },
+       /* After packet filtering, change source */
+       {
+               .hook           = nf_nat_ipv4_fn,
+               .pf             = NFPROTO_IPV4,
+               .hooknum        = NF_INET_LOCAL_IN,
+               .priority       = NF_IP_PRI_NAT_SRC,
+       },
+};
+
+int nf_nat_l3proto_ipv4_register_fn(struct net *net, const struct nf_hook_ops *ops)
+{
+       return nf_nat_register_fn(net, ops, nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
+}
+EXPORT_SYMBOL_GPL(nf_nat_l3proto_ipv4_register_fn);
+
+void nf_nat_l3proto_ipv4_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
+{
+       nf_nat_unregister_fn(net, ops, ARRAY_SIZE(nf_nat_ipv4_ops));
+}
+EXPORT_SYMBOL_GPL(nf_nat_l3proto_ipv4_unregister_fn);
 
 static int __init nf_nat_l3proto_ipv4_init(void)
 {
 
 #include <net/ip.h>
 
 static unsigned int nft_nat_do_chain(void *priv,
-                                     struct sk_buff *skb,
-                                     const struct nf_hook_state *state)
+                                    struct sk_buff *skb,
+                                    const struct nf_hook_state *state)
 {
        struct nft_pktinfo pkt;
 
        return nft_do_chain(&pkt, priv);
 }
 
-static unsigned int nft_nat_ipv4_fn(void *priv,
-                                   struct sk_buff *skb,
-                                   const struct nf_hook_state *state)
-{
-       return nf_nat_ipv4_fn(priv, skb, state, nft_nat_do_chain);
-}
-
-static unsigned int nft_nat_ipv4_in(void *priv,
-                                   struct sk_buff *skb,
-                                   const struct nf_hook_state *state)
-{
-       return nf_nat_ipv4_in(priv, skb, state, nft_nat_do_chain);
-}
-
-static unsigned int nft_nat_ipv4_out(void *priv,
-                                    struct sk_buff *skb,
-                                    const struct nf_hook_state *state)
-{
-       return nf_nat_ipv4_out(priv, skb, state, nft_nat_do_chain);
-}
-
-static unsigned int nft_nat_ipv4_local_fn(void *priv,
-                                         struct sk_buff *skb,
-                                         const struct nf_hook_state *state)
-{
-       return nf_nat_ipv4_local_fn(priv, skb, state, nft_nat_do_chain);
-}
-
 static int nft_nat_ipv4_reg(struct net *net, const struct nf_hook_ops *ops)
 {
-       int ret = nf_register_net_hook(net, ops);
-       if (ret == 0) {
-               ret = nf_ct_netns_get(net, NFPROTO_IPV4);
-               if (ret)
-                        nf_unregister_net_hook(net, ops);
-       }
-       return ret;
+       return nf_nat_l3proto_ipv4_register_fn(net, ops);
 }
 
 static void nft_nat_ipv4_unreg(struct net *net, const struct nf_hook_ops *ops)
 {
-       nf_unregister_net_hook(net, ops);
-       nf_ct_netns_put(net, NFPROTO_IPV4);
+       nf_nat_l3proto_ipv4_unregister_fn(net, ops);
 }
 
 static const struct nft_chain_type nft_chain_nat_ipv4 = {
                          (1 << NF_INET_LOCAL_OUT) |
                          (1 << NF_INET_LOCAL_IN),
        .hooks          = {
-               [NF_INET_PRE_ROUTING]   = nft_nat_ipv4_in,
-               [NF_INET_POST_ROUTING]  = nft_nat_ipv4_out,
-               [NF_INET_LOCAL_OUT]     = nft_nat_ipv4_local_fn,
-               [NF_INET_LOCAL_IN]      = nft_nat_ipv4_fn,
+               [NF_INET_PRE_ROUTING]   = nft_nat_do_chain,
+               [NF_INET_POST_ROUTING]  = nft_nat_do_chain,
+               [NF_INET_LOCAL_OUT]     = nft_nat_do_chain,
+               [NF_INET_LOCAL_IN]      = nft_nat_do_chain,
        },
        .ops_register = nft_nat_ipv4_reg,
        .ops_unregister = nft_nat_ipv4_unreg,
 
        return ip6t_do_table(skb, state, state->net->ipv6.ip6table_nat);
 }
 
-static unsigned int ip6table_nat_fn(void *priv,
-                                   struct sk_buff *skb,
-                                   const struct nf_hook_state *state)
-{
-       return nf_nat_ipv6_fn(priv, skb, state, ip6table_nat_do_chain);
-}
-
-static unsigned int ip6table_nat_in(void *priv,
-                                   struct sk_buff *skb,
-                                   const struct nf_hook_state *state)
-{
-       return nf_nat_ipv6_in(priv, skb, state, ip6table_nat_do_chain);
-}
-
-static unsigned int ip6table_nat_out(void *priv,
-                                    struct sk_buff *skb,
-                                    const struct nf_hook_state *state)
-{
-       return nf_nat_ipv6_out(priv, skb, state, ip6table_nat_do_chain);
-}
-
-static unsigned int ip6table_nat_local_fn(void *priv,
-                                         struct sk_buff *skb,
-                                         const struct nf_hook_state *state)
-{
-       return nf_nat_ipv6_local_fn(priv, skb, state, ip6table_nat_do_chain);
-}
-
 static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
-       /* Before packet filtering, change destination */
        {
-               .hook           = ip6table_nat_in,
+               .hook           = ip6table_nat_do_chain,
                .pf             = NFPROTO_IPV6,
-               .nat_hook       = true,
                .hooknum        = NF_INET_PRE_ROUTING,
                .priority       = NF_IP6_PRI_NAT_DST,
        },
-       /* After packet filtering, change source */
        {
-               .hook           = ip6table_nat_out,
+               .hook           = ip6table_nat_do_chain,
                .pf             = NFPROTO_IPV6,
-               .nat_hook       = true,
                .hooknum        = NF_INET_POST_ROUTING,
                .priority       = NF_IP6_PRI_NAT_SRC,
        },
-       /* Before packet filtering, change destination */
        {
-               .hook           = ip6table_nat_local_fn,
+               .hook           = ip6table_nat_do_chain,
                .pf             = NFPROTO_IPV6,
-               .nat_hook       = true,
                .hooknum        = NF_INET_LOCAL_OUT,
                .priority       = NF_IP6_PRI_NAT_DST,
        },
-       /* After packet filtering, change source */
        {
-               .hook           = ip6table_nat_fn,
-               .nat_hook       = true,
+               .hook           = ip6table_nat_do_chain,
                .pf             = NFPROTO_IPV6,
                .hooknum        = NF_INET_LOCAL_IN,
                .priority       = NF_IP6_PRI_NAT_SRC,
        },
 };
 
+static int ip6t_nat_register_lookups(struct net *net)
+{
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) {
+               ret = nf_nat_l3proto_ipv6_register_fn(net, &nf_nat_ipv6_ops[i]);
+               if (ret) {
+                       while (i)
+                               nf_nat_l3proto_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[--i]);
+
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void ip6t_nat_unregister_lookups(struct net *net)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++)
+               nf_nat_l3proto_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[i]);
+}
+
 static int __net_init ip6table_nat_table_init(struct net *net)
 {
        struct ip6t_replace *repl;
        if (repl == NULL)
                return -ENOMEM;
        ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl,
-                                 nf_nat_ipv6_ops, &net->ipv6.ip6table_nat);
+                                 NULL, &net->ipv6.ip6table_nat);
+       if (ret < 0) {
+               kfree(repl);
+               return ret;
+       }
+
+       ret = ip6t_nat_register_lookups(net);
+       if (ret < 0) {
+               ip6t_unregister_table(net, net->ipv6.ip6table_nat, NULL);
+               net->ipv6.ip6table_nat = NULL;
+       }
        kfree(repl);
        return ret;
 }
 {
        if (!net->ipv6.ip6table_nat)
                return;
-       ip6t_unregister_table(net, net->ipv6.ip6table_nat, nf_nat_ipv6_ops);
+       ip6t_nat_unregister_lookups(net);
+       ip6t_unregister_table(net, net->ipv6.ip6table_nat, NULL);
        net->ipv6.ip6table_nat = NULL;
 }
 
 
 }
 EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation);
 
-unsigned int
+static unsigned int
 nf_nat_ipv6_fn(void *priv, struct sk_buff *skb,
-              const struct nf_hook_state *state,
-              unsigned int (*do_chain)(void *priv,
-                                       struct sk_buff *skb,
-                                       const struct nf_hook_state *state))
+              const struct nf_hook_state *state)
 {
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
                }
        }
 
-       return nf_nat_inet_fn(priv, skb, state, do_chain);
+       return nf_nat_inet_fn(priv, skb, state);
 }
-EXPORT_SYMBOL_GPL(nf_nat_ipv6_fn);
 
-unsigned int
+static unsigned int
 nf_nat_ipv6_in(void *priv, struct sk_buff *skb,
-              const struct nf_hook_state *state,
-              unsigned int (*do_chain)(void *priv,
-                                       struct sk_buff *skb,
-                                       const struct nf_hook_state *state))
+              const struct nf_hook_state *state)
 {
        unsigned int ret;
        struct in6_addr daddr = ipv6_hdr(skb)->daddr;
 
-       ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
+       ret = nf_nat_ipv6_fn(priv, skb, state);
        if (ret != NF_DROP && ret != NF_STOLEN &&
            ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
                skb_dst_drop(skb);
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(nf_nat_ipv6_in);
 
-unsigned int
+static unsigned int
 nf_nat_ipv6_out(void *priv, struct sk_buff *skb,
-               const struct nf_hook_state *state,
-               unsigned int (*do_chain)(void *priv,
-                                        struct sk_buff *skb,
-                                        const struct nf_hook_state *state))
+               const struct nf_hook_state *state)
 {
 #ifdef CONFIG_XFRM
        const struct nf_conn *ct;
 #endif
        unsigned int ret;
 
-       ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
+       ret = nf_nat_ipv6_fn(priv, skb, state);
 #ifdef CONFIG_XFRM
        if (ret != NF_DROP && ret != NF_STOLEN &&
            !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
 #endif
        return ret;
 }
-EXPORT_SYMBOL_GPL(nf_nat_ipv6_out);
 
-unsigned int
+static unsigned int
 nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb,
-                    const struct nf_hook_state *state,
-                    unsigned int (*do_chain)(void *priv,
-                                             struct sk_buff *skb,
-                                             const struct nf_hook_state *state))
+                    const struct nf_hook_state *state)
 {
        const struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
        unsigned int ret;
        int err;
 
-       ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
+       ret = nf_nat_ipv6_fn(priv, skb, state);
        if (ret != NF_DROP && ret != NF_STOLEN &&
            (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
                enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
        }
        return ret;
 }
-EXPORT_SYMBOL_GPL(nf_nat_ipv6_local_fn);
+
+static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
+       /* Before packet filtering, change destination */
+       {
+               .hook           = nf_nat_ipv6_in,
+               .pf             = NFPROTO_IPV6,
+               .hooknum        = NF_INET_PRE_ROUTING,
+               .priority       = NF_IP6_PRI_NAT_DST,
+       },
+       /* After packet filtering, change source */
+       {
+               .hook           = nf_nat_ipv6_out,
+               .pf             = NFPROTO_IPV6,
+               .hooknum        = NF_INET_POST_ROUTING,
+               .priority       = NF_IP6_PRI_NAT_SRC,
+       },
+       /* Before packet filtering, change destination */
+       {
+               .hook           = nf_nat_ipv6_local_fn,
+               .pf             = NFPROTO_IPV6,
+               .hooknum        = NF_INET_LOCAL_OUT,
+               .priority       = NF_IP6_PRI_NAT_DST,
+       },
+       /* After packet filtering, change source */
+       {
+               .hook           = nf_nat_ipv6_fn,
+               .pf             = NFPROTO_IPV6,
+               .hooknum        = NF_INET_LOCAL_IN,
+               .priority       = NF_IP6_PRI_NAT_SRC,
+       },
+};
+
+int nf_nat_l3proto_ipv6_register_fn(struct net *net, const struct nf_hook_ops *ops)
+{
+       return nf_nat_register_fn(net, ops, nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops));
+}
+EXPORT_SYMBOL_GPL(nf_nat_l3proto_ipv6_register_fn);
+
+void nf_nat_l3proto_ipv6_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
+{
+       nf_nat_unregister_fn(net, ops, ARRAY_SIZE(nf_nat_ipv6_ops));
+}
+EXPORT_SYMBOL_GPL(nf_nat_l3proto_ipv6_unregister_fn);
 
 static int __init nf_nat_l3proto_ipv6_init(void)
 {
 
        return nft_do_chain(&pkt, priv);
 }
 
-static unsigned int nft_nat_ipv6_fn(void *priv,
-                                   struct sk_buff *skb,
-                                   const struct nf_hook_state *state)
-{
-       return nf_nat_ipv6_fn(priv, skb, state, nft_nat_do_chain);
-}
-
-static unsigned int nft_nat_ipv6_in(void *priv,
-                                   struct sk_buff *skb,
-                                   const struct nf_hook_state *state)
-{
-       return nf_nat_ipv6_in(priv, skb, state, nft_nat_do_chain);
-}
-
-static unsigned int nft_nat_ipv6_out(void *priv,
-                                    struct sk_buff *skb,
-                                    const struct nf_hook_state *state)
-{
-       return nf_nat_ipv6_out(priv, skb, state, nft_nat_do_chain);
-}
-
-static unsigned int nft_nat_ipv6_local_fn(void *priv,
-                                         struct sk_buff *skb,
-                                         const struct nf_hook_state *state)
-{
-       return nf_nat_ipv6_local_fn(priv, skb, state, nft_nat_do_chain);
-}
-
 static int nft_nat_ipv6_reg(struct net *net, const struct nf_hook_ops *ops)
 {
-       int ret = nf_register_net_hook(net, ops);
-       if (ret == 0) {
-               ret = nf_ct_netns_get(net, NFPROTO_IPV6);
-               if (ret)
-                        nf_unregister_net_hook(net, ops);
-       }
-
-       return ret;
+       return nf_nat_l3proto_ipv6_register_fn(net, ops);
 }
 
 static void nft_nat_ipv6_unreg(struct net *net, const struct nf_hook_ops *ops)
 {
-       nf_unregister_net_hook(net, ops);
-       nf_ct_netns_put(net, NFPROTO_IPV6);
+       nf_nat_l3proto_ipv6_unregister_fn(net, ops);
 }
 
 static const struct nft_chain_type nft_chain_nat_ipv6 = {
                          (1 << NF_INET_LOCAL_OUT) |
                          (1 << NF_INET_LOCAL_IN),
        .hooks          = {
-               [NF_INET_PRE_ROUTING]   = nft_nat_ipv6_in,
-               [NF_INET_POST_ROUTING]  = nft_nat_ipv6_out,
-               [NF_INET_LOCAL_OUT]     = nft_nat_ipv6_local_fn,
-               [NF_INET_LOCAL_IN]      = nft_nat_ipv6_fn,
+               [NF_INET_PRE_ROUTING]   = nft_nat_do_chain,
+               [NF_INET_POST_ROUTING]  = nft_nat_do_chain,
+               [NF_INET_LOCAL_OUT]     = nft_nat_do_chain,
+               [NF_INET_LOCAL_IN]      = nft_nat_do_chain,
        },
        .ops_register           = nft_nat_ipv6_reg,
        .ops_unregister         = nft_nat_ipv6_unreg,
 
 
 unsigned int
 nf_nat_inet_fn(void *priv, struct sk_buff *skb,
-              const struct nf_hook_state *state,
-              unsigned int (*do_chain)(void *priv,
-                                       struct sk_buff *skb,
-                                       const struct nf_hook_state *state))
+              const struct nf_hook_state *state)
 {
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
                 * or local packets.
                 */
                if (!nf_nat_initialized(ct, maniptype)) {
+                       struct nf_nat_lookup_hook_priv *lpriv = priv;
+                       struct nf_hook_entries *e = rcu_dereference(lpriv->entries);
                        unsigned int ret;
-
-                       ret = do_chain(priv, skb, state);
-                       if (ret != NF_ACCEPT)
-                               return ret;
-
-                       if (nf_nat_initialized(ct, HOOK2MANIP(state->hook)))
-                               break;
-
+                       int i;
+
+                       if (!e)
+                               goto null_bind;
+
+                       for (i = 0; i < e->num_hook_entries; i++) {
+                               ret = e->hooks[i].hook(e->hooks[i].priv, skb,
+                                                      state);
+                               if (ret != NF_ACCEPT)
+                                       return ret;
+                               if (nf_nat_initialized(ct, maniptype))
+                                       goto do_nat;
+                       }
+null_bind:
                        ret = nf_nat_alloc_null_binding(ct, state->hook);
                        if (ret != NF_ACCEPT)
                                return ret;
                if (nf_nat_oif_changed(state->hook, ctinfo, nat, state->out))
                        goto oif_changed;
        }
-
+do_nat:
        return nf_nat_packet(ct, ctinfo, state->hook, skb);
 
 oif_changed: