1
0
Fork 0

netfilter: nf_tables: remove multihook chains and families

Since NFPROTO_INET is handled from the core, we don't need to maintain
extra infrastructure in nf_tables to handle the double hook
registration, one for IPv4 and another for IPv6.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Pablo Neira Ayuso 2017-12-09 15:40:25 +01:00
parent 12355d3670
commit c974a3a364
9 changed files with 49 additions and 78 deletions

View file

@ -902,8 +902,6 @@ struct nft_stats {
struct u64_stats_sync syncp; struct u64_stats_sync syncp;
}; };
#define NFT_HOOK_OPS_MAX 2
/** /**
* struct nft_base_chain - nf_tables base chain * struct nft_base_chain - nf_tables base chain
* *
@ -915,7 +913,7 @@ struct nft_stats {
* @dev_name: device name that this base chain is attached to (if any) * @dev_name: device name that this base chain is attached to (if any)
*/ */
struct nft_base_chain { struct nft_base_chain {
struct nf_hook_ops ops[NFT_HOOK_OPS_MAX]; struct nf_hook_ops ops;
const struct nf_chain_type *type; const struct nf_chain_type *type;
u8 policy; u8 policy;
u8 flags; u8 flags;
@ -976,8 +974,6 @@ enum nft_af_flags {
* @owner: module owner * @owner: module owner
* @tables: used internally * @tables: used internally
* @flags: family flags * @flags: family flags
* @nops: number of hook ops in this family
* @hook_ops_init: initialization function for chain hook ops
* @hooks: hookfn overrides for packet validation * @hooks: hookfn overrides for packet validation
*/ */
struct nft_af_info { struct nft_af_info {
@ -987,9 +983,6 @@ struct nft_af_info {
struct module *owner; struct module *owner;
struct list_head tables; struct list_head tables;
u32 flags; u32 flags;
unsigned int nops;
void (*hook_ops_init)(struct nf_hook_ops *,
unsigned int);
nf_hookfn *hooks[NF_MAX_HOOKS]; nf_hookfn *hooks[NF_MAX_HOOKS];
}; };

View file

@ -46,7 +46,6 @@ static struct nft_af_info nft_af_bridge __read_mostly = {
.family = NFPROTO_BRIDGE, .family = NFPROTO_BRIDGE,
.nhooks = NF_BR_NUMHOOKS, .nhooks = NF_BR_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.nops = 1,
.hooks = { .hooks = {
[NF_BR_PRE_ROUTING] = nft_do_chain_bridge, [NF_BR_PRE_ROUTING] = nft_do_chain_bridge,
[NF_BR_LOCAL_IN] = nft_do_chain_bridge, [NF_BR_LOCAL_IN] = nft_do_chain_bridge,

View file

@ -31,7 +31,6 @@ static struct nft_af_info nft_af_arp __read_mostly = {
.family = NFPROTO_ARP, .family = NFPROTO_ARP,
.nhooks = NF_ARP_NUMHOOKS, .nhooks = NF_ARP_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.nops = 1,
.hooks = { .hooks = {
[NF_ARP_IN] = nft_do_chain_arp, [NF_ARP_IN] = nft_do_chain_arp,
[NF_ARP_OUT] = nft_do_chain_arp, [NF_ARP_OUT] = nft_do_chain_arp,

View file

@ -49,7 +49,6 @@ static struct nft_af_info nft_af_ipv4 __read_mostly = {
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.nhooks = NF_INET_NUMHOOKS, .nhooks = NF_INET_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.nops = 1,
.hooks = { .hooks = {
[NF_INET_LOCAL_IN] = nft_do_chain_ipv4, [NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
[NF_INET_LOCAL_OUT] = nft_ipv4_output, [NF_INET_LOCAL_OUT] = nft_ipv4_output,

View file

@ -46,7 +46,6 @@ static struct nft_af_info nft_af_ipv6 __read_mostly = {
.family = NFPROTO_IPV6, .family = NFPROTO_IPV6,
.nhooks = NF_INET_NUMHOOKS, .nhooks = NF_INET_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.nops = 1,
.hooks = { .hooks = {
[NF_INET_LOCAL_IN] = nft_do_chain_ipv6, [NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
[NF_INET_LOCAL_OUT] = nft_ipv6_output, [NF_INET_LOCAL_OUT] = nft_ipv6_output,

View file

@ -139,29 +139,26 @@ static void nft_trans_destroy(struct nft_trans *trans)
kfree(trans); kfree(trans);
} }
static int nf_tables_register_hooks(struct net *net, static int nf_tables_register_hook(struct net *net,
const struct nft_table *table, const struct nft_table *table,
struct nft_chain *chain, struct nft_chain *chain)
unsigned int hook_nops)
{ {
if (table->flags & NFT_TABLE_F_DORMANT || if (table->flags & NFT_TABLE_F_DORMANT ||
!nft_is_base_chain(chain)) !nft_is_base_chain(chain))
return 0; return 0;
return nf_register_net_hooks(net, nft_base_chain(chain)->ops, return nf_register_net_hook(net, &nft_base_chain(chain)->ops);
hook_nops);
} }
static void nf_tables_unregister_hooks(struct net *net, static void nf_tables_unregister_hook(struct net *net,
const struct nft_table *table, const struct nft_table *table,
struct nft_chain *chain, struct nft_chain *chain)
unsigned int hook_nops)
{ {
if (table->flags & NFT_TABLE_F_DORMANT || if (table->flags & NFT_TABLE_F_DORMANT ||
!nft_is_base_chain(chain)) !nft_is_base_chain(chain))
return; return;
nf_unregister_net_hooks(net, nft_base_chain(chain)->ops, hook_nops); nf_unregister_net_hook(net, &nft_base_chain(chain)->ops);
} }
static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type) static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
@ -595,8 +592,7 @@ static void _nf_tables_table_disable(struct net *net,
if (cnt && i++ == cnt) if (cnt && i++ == cnt)
break; break;
nf_unregister_net_hooks(net, nft_base_chain(chain)->ops, nf_unregister_net_hook(net, &nft_base_chain(chain)->ops);
afi->nops);
} }
} }
@ -613,8 +609,7 @@ static int nf_tables_table_enable(struct net *net,
if (!nft_is_base_chain(chain)) if (!nft_is_base_chain(chain))
continue; continue;
err = nf_register_net_hooks(net, nft_base_chain(chain)->ops, err = nf_register_net_hook(net, &nft_base_chain(chain)->ops);
afi->nops);
if (err < 0) if (err < 0)
goto err; goto err;
@ -1026,7 +1021,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
if (nft_is_base_chain(chain)) { if (nft_is_base_chain(chain)) {
const struct nft_base_chain *basechain = nft_base_chain(chain); const struct nft_base_chain *basechain = nft_base_chain(chain);
const struct nf_hook_ops *ops = &basechain->ops[0]; const struct nf_hook_ops *ops = &basechain->ops;
struct nlattr *nest; struct nlattr *nest;
nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
@ -1252,8 +1247,8 @@ static void nf_tables_chain_destroy(struct nft_chain *chain)
free_percpu(basechain->stats); free_percpu(basechain->stats);
if (basechain->stats) if (basechain->stats)
static_branch_dec(&nft_counters_enabled); static_branch_dec(&nft_counters_enabled);
if (basechain->ops[0].dev != NULL) if (basechain->ops.dev != NULL)
dev_put(basechain->ops[0].dev); dev_put(basechain->ops.dev);
kfree(chain->name); kfree(chain->name);
kfree(basechain); kfree(basechain);
} else { } else {
@ -1354,7 +1349,6 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
struct nft_stats __percpu *stats; struct nft_stats __percpu *stats;
struct net *net = ctx->net; struct net *net = ctx->net;
struct nft_chain *chain; struct nft_chain *chain;
unsigned int i;
int err; int err;
if (table->use == UINT_MAX) if (table->use == UINT_MAX)
@ -1393,21 +1387,18 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
basechain->type = hook.type; basechain->type = hook.type;
chain = &basechain->chain; chain = &basechain->chain;
for (i = 0; i < afi->nops; i++) { ops = &basechain->ops;
ops = &basechain->ops[i]; ops->pf = family;
ops->pf = family; ops->hooknum = hook.num;
ops->hooknum = hook.num; ops->priority = hook.priority;
ops->priority = hook.priority; ops->priv = chain;
ops->priv = chain; ops->hook = afi->hooks[ops->hooknum];
ops->hook = afi->hooks[ops->hooknum]; ops->dev = hook.dev;
ops->dev = hook.dev; if (hookfn)
if (hookfn) ops->hook = hookfn;
ops->hook = hookfn;
if (afi->hook_ops_init) if (basechain->type->type == NFT_CHAIN_T_NAT)
afi->hook_ops_init(ops, i); ops->nat_hook = true;
if (basechain->type->type == NFT_CHAIN_T_NAT)
ops->nat_hook = true;
}
chain->flags |= NFT_BASE_CHAIN; chain->flags |= NFT_BASE_CHAIN;
basechain->policy = policy; basechain->policy = policy;
@ -1425,7 +1416,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
goto err1; goto err1;
} }
err = nf_tables_register_hooks(net, table, chain, afi->nops); err = nf_tables_register_hook(net, table, chain);
if (err < 0) if (err < 0)
goto err1; goto err1;
@ -1439,7 +1430,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
return 0; return 0;
err2: err2:
nf_tables_unregister_hooks(net, table, chain, afi->nops); nf_tables_unregister_hook(net, table, chain);
err1: err1:
nf_tables_chain_destroy(chain); nf_tables_chain_destroy(chain);
@ -1452,14 +1443,13 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
const struct nlattr * const *nla = ctx->nla; const struct nlattr * const *nla = ctx->nla;
struct nft_table *table = ctx->table; struct nft_table *table = ctx->table;
struct nft_chain *chain = ctx->chain; struct nft_chain *chain = ctx->chain;
struct nft_af_info *afi = ctx->afi;
struct nft_base_chain *basechain; struct nft_base_chain *basechain;
struct nft_stats *stats = NULL; struct nft_stats *stats = NULL;
struct nft_chain_hook hook; struct nft_chain_hook hook;
const struct nlattr *name; const struct nlattr *name;
struct nf_hook_ops *ops; struct nf_hook_ops *ops;
struct nft_trans *trans; struct nft_trans *trans;
int err, i; int err;
if (nla[NFTA_CHAIN_HOOK]) { if (nla[NFTA_CHAIN_HOOK]) {
if (!nft_is_base_chain(chain)) if (!nft_is_base_chain(chain))
@ -1476,14 +1466,12 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
return -EBUSY; return -EBUSY;
} }
for (i = 0; i < afi->nops; i++) { ops = &basechain->ops;
ops = &basechain->ops[i]; if (ops->hooknum != hook.num ||
if (ops->hooknum != hook.num || ops->priority != hook.priority ||
ops->priority != hook.priority || ops->dev != hook.dev) {
ops->dev != hook.dev) { nft_chain_release_hook(&hook);
nft_chain_release_hook(&hook); return -EBUSY;
return -EBUSY;
}
} }
nft_chain_release_hook(&hook); nft_chain_release_hook(&hook);
} }
@ -5134,10 +5122,9 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
case NFT_MSG_DELCHAIN: case NFT_MSG_DELCHAIN:
list_del_rcu(&trans->ctx.chain->list); list_del_rcu(&trans->ctx.chain->list);
nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN); nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
nf_tables_unregister_hooks(trans->ctx.net, nf_tables_unregister_hook(trans->ctx.net,
trans->ctx.table, trans->ctx.table,
trans->ctx.chain, trans->ctx.chain);
trans->ctx.afi->nops);
break; break;
case NFT_MSG_NEWRULE: case NFT_MSG_NEWRULE:
nft_clear(trans->ctx.net, nft_trans_rule(trans)); nft_clear(trans->ctx.net, nft_trans_rule(trans));
@ -5274,10 +5261,9 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
} else { } else {
trans->ctx.table->use--; trans->ctx.table->use--;
list_del_rcu(&trans->ctx.chain->list); list_del_rcu(&trans->ctx.chain->list);
nf_tables_unregister_hooks(trans->ctx.net, nf_tables_unregister_hook(trans->ctx.net,
trans->ctx.table, trans->ctx.table,
trans->ctx.chain, trans->ctx.chain);
trans->ctx.afi->nops);
} }
break; break;
case NFT_MSG_DELCHAIN: case NFT_MSG_DELCHAIN:
@ -5378,7 +5364,7 @@ int nft_chain_validate_hooks(const struct nft_chain *chain,
if (nft_is_base_chain(chain)) { if (nft_is_base_chain(chain)) {
basechain = nft_base_chain(chain); basechain = nft_base_chain(chain);
if ((1 << basechain->ops[0].hooknum) & hook_flags) if ((1 << basechain->ops.hooknum) & hook_flags)
return 0; return 0;
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -5866,8 +5852,7 @@ int __nft_release_basechain(struct nft_ctx *ctx)
BUG_ON(!nft_is_base_chain(ctx->chain)); BUG_ON(!nft_is_base_chain(ctx->chain));
nf_tables_unregister_hooks(ctx->net, ctx->chain->table, ctx->chain, nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
ctx->afi->nops);
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) { list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
list_del(&rule->list); list_del(&rule->list);
ctx->chain->use--; ctx->chain->use--;
@ -5896,8 +5881,7 @@ static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
list_for_each_entry_safe(table, nt, &afi->tables, list) { list_for_each_entry_safe(table, nt, &afi->tables, list) {
list_for_each_entry(chain, &table->chains, list) list_for_each_entry(chain, &table->chains, list)
nf_tables_unregister_hooks(net, table, chain, nf_tables_unregister_hook(net, table, chain);
afi->nops);
/* No packets are walking on these chains anymore. */ /* No packets are walking on these chains anymore. */
ctx.table = table; ctx.table = table;
list_for_each_entry(chain, &table->chains, list) { list_for_each_entry(chain, &table->chains, list) {

View file

@ -74,7 +74,6 @@ static struct nft_af_info nft_af_inet __read_mostly = {
.family = NFPROTO_INET, .family = NFPROTO_INET,
.nhooks = NF_INET_NUMHOOKS, .nhooks = NF_INET_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.nops = 1,
.hooks = { .hooks = {
[NF_INET_LOCAL_IN] = nft_do_chain_inet, [NF_INET_LOCAL_IN] = nft_do_chain_inet,
[NF_INET_LOCAL_OUT] = nft_inet_output, [NF_INET_LOCAL_OUT] = nft_inet_output,

View file

@ -43,7 +43,6 @@ static struct nft_af_info nft_af_netdev __read_mostly = {
.nhooks = NF_NETDEV_NUMHOOKS, .nhooks = NF_NETDEV_NUMHOOKS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.flags = NFT_AF_NEEDS_DEV, .flags = NFT_AF_NEEDS_DEV,
.nops = 1,
.hooks = { .hooks = {
[NF_NETDEV_INGRESS] = nft_do_chain_netdev, [NF_NETDEV_INGRESS] = nft_do_chain_netdev,
}, },
@ -98,7 +97,7 @@ static void nft_netdev_event(unsigned long event, struct net_device *dev,
__nft_release_basechain(ctx); __nft_release_basechain(ctx);
break; break;
case NETDEV_CHANGENAME: case NETDEV_CHANGENAME:
if (dev->ifindex != basechain->ops[0].dev->ifindex) if (dev->ifindex != basechain->ops.dev->ifindex)
return; return;
strncpy(basechain->dev_name, dev->name, IFNAMSIZ); strncpy(basechain->dev_name, dev->name, IFNAMSIZ);

View file

@ -169,7 +169,7 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par,
if (nft_is_base_chain(ctx->chain)) { if (nft_is_base_chain(ctx->chain)) {
const struct nft_base_chain *basechain = const struct nft_base_chain *basechain =
nft_base_chain(ctx->chain); nft_base_chain(ctx->chain);
const struct nf_hook_ops *ops = &basechain->ops[0]; const struct nf_hook_ops *ops = &basechain->ops;
par->hook_mask = 1 << ops->hooknum; par->hook_mask = 1 << ops->hooknum;
} else { } else {
@ -302,7 +302,7 @@ static int nft_target_validate(const struct nft_ctx *ctx,
if (nft_is_base_chain(ctx->chain)) { if (nft_is_base_chain(ctx->chain)) {
const struct nft_base_chain *basechain = const struct nft_base_chain *basechain =
nft_base_chain(ctx->chain); nft_base_chain(ctx->chain);
const struct nf_hook_ops *ops = &basechain->ops[0]; const struct nf_hook_ops *ops = &basechain->ops;
hook_mask = 1 << ops->hooknum; hook_mask = 1 << ops->hooknum;
if (target->hooks && !(hook_mask & target->hooks)) if (target->hooks && !(hook_mask & target->hooks))
@ -383,7 +383,7 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
if (nft_is_base_chain(ctx->chain)) { if (nft_is_base_chain(ctx->chain)) {
const struct nft_base_chain *basechain = const struct nft_base_chain *basechain =
nft_base_chain(ctx->chain); nft_base_chain(ctx->chain);
const struct nf_hook_ops *ops = &basechain->ops[0]; const struct nf_hook_ops *ops = &basechain->ops;
par->hook_mask = 1 << ops->hooknum; par->hook_mask = 1 << ops->hooknum;
} else { } else {
@ -481,7 +481,7 @@ static int nft_match_validate(const struct nft_ctx *ctx,
if (nft_is_base_chain(ctx->chain)) { if (nft_is_base_chain(ctx->chain)) {
const struct nft_base_chain *basechain = const struct nft_base_chain *basechain =
nft_base_chain(ctx->chain); nft_base_chain(ctx->chain);
const struct nf_hook_ops *ops = &basechain->ops[0]; const struct nf_hook_ops *ops = &basechain->ops;
hook_mask = 1 << ops->hooknum; hook_mask = 1 << ops->hooknum;
if (match->hooks && !(hook_mask & match->hooks)) if (match->hooks && !(hook_mask & match->hooks))