* @owner: module owner
* @hook_mask: mask of valid hooks
* @hooks: array of hook functions
- * @init: chain initialization function
- * @free: chain release function
+ * @ops_register: base chain register function
+ * @ops_unregister: base chain unregister function
*/
struct nft_chain_type {
const char *name;
struct module *owner;
unsigned int hook_mask;
nf_hookfn *hooks[NF_MAX_HOOKS];
- int (*init)(struct nft_ctx *ctx);
- void (*free)(struct nft_ctx *ctx);
+ int (*ops_register)(struct net *net, const struct nf_hook_ops *ops);
+ void (*ops_unregister)(struct net *net, const struct nf_hook_ops *ops);
};
int nft_chain_validate_dependency(const struct nft_chain *chain,
return nf_nat_ipv4_local_fn(priv, skb, state, nft_nat_do_chain);
}
-static int nft_nat_ipv4_init(struct nft_ctx *ctx)
+static int nft_nat_ipv4_reg(struct net *net, const struct nf_hook_ops *ops)
{
- return nf_ct_netns_get(ctx->net, ctx->family);
+ 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;
}
-static void nft_nat_ipv4_free(struct nft_ctx *ctx)
+static void nft_nat_ipv4_unreg(struct net *net, const struct nf_hook_ops *ops)
{
- nf_ct_netns_put(ctx->net, ctx->family);
+ nf_unregister_net_hook(net, ops);
+ nf_ct_netns_put(net, NFPROTO_IPV4);
}
static const struct nft_chain_type nft_chain_nat_ipv4 = {
[NF_INET_LOCAL_OUT] = nft_nat_ipv4_local_fn,
[NF_INET_LOCAL_IN] = nft_nat_ipv4_fn,
},
- .init = nft_nat_ipv4_init,
- .free = nft_nat_ipv4_free,
+ .ops_register = nft_nat_ipv4_reg,
+ .ops_unregister = nft_nat_ipv4_unreg,
};
static int __init nft_chain_nat_init(void)
return nf_nat_ipv6_local_fn(priv, skb, state, nft_nat_do_chain);
}
-static int nft_nat_ipv6_init(struct nft_ctx *ctx)
+static int nft_nat_ipv6_reg(struct net *net, const struct nf_hook_ops *ops)
{
- return nf_ct_netns_get(ctx->net, ctx->family);
+ 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;
}
-static void nft_nat_ipv6_free(struct nft_ctx *ctx)
+static void nft_nat_ipv6_unreg(struct net *net, const struct nf_hook_ops *ops)
{
- nf_ct_netns_put(ctx->net, ctx->family);
+ nf_unregister_net_hook(net, ops);
+ nf_ct_netns_put(net, NFPROTO_IPV6);
}
static const struct nft_chain_type nft_chain_nat_ipv6 = {
[NF_INET_LOCAL_OUT] = nft_nat_ipv6_local_fn,
[NF_INET_LOCAL_IN] = nft_nat_ipv6_fn,
},
- .init = nft_nat_ipv6_init,
- .free = nft_nat_ipv6_free,
+ .ops_register = nft_nat_ipv6_reg,
+ .ops_unregister = nft_nat_ipv6_unreg,
};
static int __init nft_chain_nat_ipv6_init(void)
const struct nft_table *table,
struct nft_chain *chain)
{
+ const struct nft_base_chain *basechain;
struct nf_hook_ops *ops;
int ret;
!nft_is_base_chain(chain))
return 0;
- ops = &nft_base_chain(chain)->ops;
+ basechain = nft_base_chain(chain);
+ ops = &basechain->ops;
+
+ if (basechain->type->ops_register)
+ return basechain->type->ops_register(net, ops);
+
ret = nf_register_net_hook(net, ops);
if (ret == -EBUSY && nf_tables_allow_nat_conflict(net, ops)) {
ops->nat_hook = false;
const struct nft_table *table,
struct nft_chain *chain)
{
+ const struct nft_base_chain *basechain;
+ const struct nf_hook_ops *ops;
+
if (table->flags & NFT_TABLE_F_DORMANT ||
!nft_is_base_chain(chain))
return;
+ basechain = nft_base_chain(chain);
+ ops = &basechain->ops;
+
+ if (basechain->type->ops_unregister)
+ return basechain->type->ops_unregister(net, ops);
- nf_unregister_net_hook(net, &nft_base_chain(chain)->ops);
+ nf_unregister_net_hook(net, ops);
}
static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
if (nft_is_base_chain(chain)) {
struct nft_base_chain *basechain = nft_base_chain(chain);
- if (basechain->type->free)
- basechain->type->free(ctx);
module_put(basechain->type->owner);
free_percpu(basechain->stats);
if (basechain->stats)
}
basechain->type = hook.type;
- if (basechain->type->init)
- basechain->type->init(ctx);
-
chain = &basechain->chain;
ops = &basechain->ops;