You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
12 KiB
390 lines
12 KiB
From: Pablo Neira Ayuso <pablo@netfilter.org>
|
|
Date: Sat, 9 Dec 2017 15:40:25 +0100
|
|
Subject: [PATCH] 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>
|
|
---
|
|
|
|
--- a/include/net/netfilter/nf_tables.h
|
|
+++ b/include/net/netfilter/nf_tables.h
|
|
@@ -897,8 +897,6 @@ struct nft_stats {
|
|
struct u64_stats_sync syncp;
|
|
};
|
|
|
|
-#define NFT_HOOK_OPS_MAX 2
|
|
-
|
|
/**
|
|
* struct nft_base_chain - nf_tables base chain
|
|
*
|
|
@@ -910,7 +908,7 @@ struct nft_stats {
|
|
* @dev_name: device name that this base chain is attached to (if any)
|
|
*/
|
|
struct nft_base_chain {
|
|
- struct nf_hook_ops ops[NFT_HOOK_OPS_MAX];
|
|
+ struct nf_hook_ops ops;
|
|
const struct nf_chain_type *type;
|
|
u8 policy;
|
|
u8 flags;
|
|
@@ -971,8 +969,6 @@ enum nft_af_flags {
|
|
* @owner: module owner
|
|
* @tables: used internally
|
|
* @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
|
|
*/
|
|
struct nft_af_info {
|
|
@@ -982,9 +978,6 @@ struct nft_af_info {
|
|
struct module *owner;
|
|
struct list_head tables;
|
|
u32 flags;
|
|
- unsigned int nops;
|
|
- void (*hook_ops_init)(struct nf_hook_ops *,
|
|
- unsigned int);
|
|
nf_hookfn *hooks[NF_MAX_HOOKS];
|
|
};
|
|
|
|
--- a/net/bridge/netfilter/nf_tables_bridge.c
|
|
+++ b/net/bridge/netfilter/nf_tables_bridge.c
|
|
@@ -46,7 +46,6 @@ static struct nft_af_info nft_af_bridge
|
|
.family = NFPROTO_BRIDGE,
|
|
.nhooks = NF_BR_NUMHOOKS,
|
|
.owner = THIS_MODULE,
|
|
- .nops = 1,
|
|
.hooks = {
|
|
[NF_BR_PRE_ROUTING] = nft_do_chain_bridge,
|
|
[NF_BR_LOCAL_IN] = nft_do_chain_bridge,
|
|
--- a/net/ipv4/netfilter/nf_tables_arp.c
|
|
+++ b/net/ipv4/netfilter/nf_tables_arp.c
|
|
@@ -31,7 +31,6 @@ static struct nft_af_info nft_af_arp __r
|
|
.family = NFPROTO_ARP,
|
|
.nhooks = NF_ARP_NUMHOOKS,
|
|
.owner = THIS_MODULE,
|
|
- .nops = 1,
|
|
.hooks = {
|
|
[NF_ARP_IN] = nft_do_chain_arp,
|
|
[NF_ARP_OUT] = nft_do_chain_arp,
|
|
--- a/net/ipv4/netfilter/nf_tables_ipv4.c
|
|
+++ b/net/ipv4/netfilter/nf_tables_ipv4.c
|
|
@@ -49,7 +49,6 @@ static struct nft_af_info nft_af_ipv4 __
|
|
.family = NFPROTO_IPV4,
|
|
.nhooks = NF_INET_NUMHOOKS,
|
|
.owner = THIS_MODULE,
|
|
- .nops = 1,
|
|
.hooks = {
|
|
[NF_INET_LOCAL_IN] = nft_do_chain_ipv4,
|
|
[NF_INET_LOCAL_OUT] = nft_ipv4_output,
|
|
--- a/net/ipv6/netfilter/nf_tables_ipv6.c
|
|
+++ b/net/ipv6/netfilter/nf_tables_ipv6.c
|
|
@@ -46,7 +46,6 @@ static struct nft_af_info nft_af_ipv6 __
|
|
.family = NFPROTO_IPV6,
|
|
.nhooks = NF_INET_NUMHOOKS,
|
|
.owner = THIS_MODULE,
|
|
- .nops = 1,
|
|
.hooks = {
|
|
[NF_INET_LOCAL_IN] = nft_do_chain_ipv6,
|
|
[NF_INET_LOCAL_OUT] = nft_ipv6_output,
|
|
--- a/net/netfilter/nf_tables_api.c
|
|
+++ b/net/netfilter/nf_tables_api.c
|
|
@@ -139,29 +139,26 @@ static void nft_trans_destroy(struct nft
|
|
kfree(trans);
|
|
}
|
|
|
|
-static int nf_tables_register_hooks(struct net *net,
|
|
- const struct nft_table *table,
|
|
- struct nft_chain *chain,
|
|
- unsigned int hook_nops)
|
|
+static int nf_tables_register_hook(struct net *net,
|
|
+ const struct nft_table *table,
|
|
+ struct nft_chain *chain)
|
|
{
|
|
if (table->flags & NFT_TABLE_F_DORMANT ||
|
|
!nft_is_base_chain(chain))
|
|
return 0;
|
|
|
|
- return nf_register_net_hooks(net, nft_base_chain(chain)->ops,
|
|
- hook_nops);
|
|
+ return nf_register_net_hook(net, &nft_base_chain(chain)->ops);
|
|
}
|
|
|
|
-static void nf_tables_unregister_hooks(struct net *net,
|
|
- const struct nft_table *table,
|
|
- struct nft_chain *chain,
|
|
- unsigned int hook_nops)
|
|
+static void nf_tables_unregister_hook(struct net *net,
|
|
+ const struct nft_table *table,
|
|
+ struct nft_chain *chain)
|
|
{
|
|
if (table->flags & NFT_TABLE_F_DORMANT ||
|
|
!nft_is_base_chain(chain))
|
|
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)
|
|
@@ -624,8 +621,7 @@ static void _nf_tables_table_disable(str
|
|
if (cnt && i++ == cnt)
|
|
break;
|
|
|
|
- nf_unregister_net_hooks(net, nft_base_chain(chain)->ops,
|
|
- afi->nops);
|
|
+ nf_unregister_net_hook(net, &nft_base_chain(chain)->ops);
|
|
}
|
|
}
|
|
|
|
@@ -642,8 +638,7 @@ static int nf_tables_table_enable(struct
|
|
if (!nft_is_base_chain(chain))
|
|
continue;
|
|
|
|
- err = nf_register_net_hooks(net, nft_base_chain(chain)->ops,
|
|
- afi->nops);
|
|
+ err = nf_register_net_hook(net, &nft_base_chain(chain)->ops);
|
|
if (err < 0)
|
|
goto err;
|
|
|
|
@@ -1055,7 +1050,7 @@ static int nf_tables_fill_chain_info(str
|
|
|
|
if (nft_is_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;
|
|
|
|
nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
|
|
@@ -1283,8 +1278,8 @@ static void nf_tables_chain_destroy(stru
|
|
free_percpu(basechain->stats);
|
|
if (basechain->stats)
|
|
static_branch_dec(&nft_counters_enabled);
|
|
- if (basechain->ops[0].dev != NULL)
|
|
- dev_put(basechain->ops[0].dev);
|
|
+ if (basechain->ops.dev != NULL)
|
|
+ dev_put(basechain->ops.dev);
|
|
kfree(chain->name);
|
|
kfree(basechain);
|
|
} else {
|
|
@@ -1380,7 +1375,6 @@ static int nf_tables_addchain(struct nft
|
|
struct nft_stats __percpu *stats;
|
|
struct net *net = ctx->net;
|
|
struct nft_chain *chain;
|
|
- unsigned int i;
|
|
int err;
|
|
|
|
if (table->use == UINT_MAX)
|
|
@@ -1419,21 +1413,18 @@ static int nf_tables_addchain(struct nft
|
|
basechain->type = hook.type;
|
|
chain = &basechain->chain;
|
|
|
|
- for (i = 0; i < afi->nops; i++) {
|
|
- ops = &basechain->ops[i];
|
|
- ops->pf = family;
|
|
- ops->hooknum = hook.num;
|
|
- ops->priority = hook.priority;
|
|
- ops->priv = chain;
|
|
- ops->hook = afi->hooks[ops->hooknum];
|
|
- ops->dev = hook.dev;
|
|
- if (hookfn)
|
|
- ops->hook = hookfn;
|
|
- if (afi->hook_ops_init)
|
|
- afi->hook_ops_init(ops, i);
|
|
- if (basechain->type->type == NFT_CHAIN_T_NAT)
|
|
- ops->nat_hook = true;
|
|
- }
|
|
+ ops = &basechain->ops;
|
|
+ ops->pf = family;
|
|
+ ops->hooknum = hook.num;
|
|
+ ops->priority = hook.priority;
|
|
+ ops->priv = chain;
|
|
+ ops->hook = afi->hooks[ops->hooknum];
|
|
+ ops->dev = hook.dev;
|
|
+ if (hookfn)
|
|
+ ops->hook = hookfn;
|
|
+
|
|
+ if (basechain->type->type == NFT_CHAIN_T_NAT)
|
|
+ ops->nat_hook = true;
|
|
|
|
chain->flags |= NFT_BASE_CHAIN;
|
|
basechain->policy = policy;
|
|
@@ -1451,7 +1442,7 @@ static int nf_tables_addchain(struct nft
|
|
goto err1;
|
|
}
|
|
|
|
- err = nf_tables_register_hooks(net, table, chain, afi->nops);
|
|
+ err = nf_tables_register_hook(net, table, chain);
|
|
if (err < 0)
|
|
goto err1;
|
|
|
|
@@ -1465,7 +1456,7 @@ static int nf_tables_addchain(struct nft
|
|
|
|
return 0;
|
|
err2:
|
|
- nf_tables_unregister_hooks(net, table, chain, afi->nops);
|
|
+ nf_tables_unregister_hook(net, table, chain);
|
|
err1:
|
|
nf_tables_chain_destroy(chain);
|
|
|
|
@@ -1478,13 +1469,12 @@ static int nf_tables_updchain(struct nft
|
|
const struct nlattr * const *nla = ctx->nla;
|
|
struct nft_table *table = ctx->table;
|
|
struct nft_chain *chain = ctx->chain;
|
|
- struct nft_af_info *afi = ctx->afi;
|
|
struct nft_base_chain *basechain;
|
|
struct nft_stats *stats = NULL;
|
|
struct nft_chain_hook hook;
|
|
struct nf_hook_ops *ops;
|
|
struct nft_trans *trans;
|
|
- int err, i;
|
|
+ int err;
|
|
|
|
if (nla[NFTA_CHAIN_HOOK]) {
|
|
if (!nft_is_base_chain(chain))
|
|
@@ -1501,14 +1491,12 @@ static int nf_tables_updchain(struct nft
|
|
return -EBUSY;
|
|
}
|
|
|
|
- for (i = 0; i < afi->nops; i++) {
|
|
- ops = &basechain->ops[i];
|
|
- if (ops->hooknum != hook.num ||
|
|
- ops->priority != hook.priority ||
|
|
- ops->dev != hook.dev) {
|
|
- nft_chain_release_hook(&hook);
|
|
- return -EBUSY;
|
|
- }
|
|
+ ops = &basechain->ops;
|
|
+ if (ops->hooknum != hook.num ||
|
|
+ ops->priority != hook.priority ||
|
|
+ ops->dev != hook.dev) {
|
|
+ nft_chain_release_hook(&hook);
|
|
+ return -EBUSY;
|
|
}
|
|
nft_chain_release_hook(&hook);
|
|
}
|
|
@@ -5129,10 +5117,9 @@ static int nf_tables_commit(struct net *
|
|
case NFT_MSG_DELCHAIN:
|
|
list_del_rcu(&trans->ctx.chain->list);
|
|
nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
|
|
- nf_tables_unregister_hooks(trans->ctx.net,
|
|
- trans->ctx.table,
|
|
- trans->ctx.chain,
|
|
- trans->ctx.afi->nops);
|
|
+ nf_tables_unregister_hook(trans->ctx.net,
|
|
+ trans->ctx.table,
|
|
+ trans->ctx.chain);
|
|
break;
|
|
case NFT_MSG_NEWRULE:
|
|
nft_clear(trans->ctx.net, nft_trans_rule(trans));
|
|
@@ -5269,10 +5256,9 @@ static int nf_tables_abort(struct net *n
|
|
} else {
|
|
trans->ctx.table->use--;
|
|
list_del_rcu(&trans->ctx.chain->list);
|
|
- nf_tables_unregister_hooks(trans->ctx.net,
|
|
- trans->ctx.table,
|
|
- trans->ctx.chain,
|
|
- trans->ctx.afi->nops);
|
|
+ nf_tables_unregister_hook(trans->ctx.net,
|
|
+ trans->ctx.table,
|
|
+ trans->ctx.chain);
|
|
}
|
|
break;
|
|
case NFT_MSG_DELCHAIN:
|
|
@@ -5375,7 +5361,7 @@ int nft_chain_validate_hooks(const struc
|
|
if (nft_is_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 -EOPNOTSUPP;
|
|
@@ -5857,8 +5843,7 @@ int __nft_release_basechain(struct nft_c
|
|
|
|
BUG_ON(!nft_is_base_chain(ctx->chain));
|
|
|
|
- nf_tables_unregister_hooks(ctx->net, ctx->chain->table, ctx->chain,
|
|
- ctx->afi->nops);
|
|
+ nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
|
|
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
|
|
list_del(&rule->list);
|
|
ctx->chain->use--;
|
|
@@ -5887,8 +5872,7 @@ static void __nft_release_afinfo(struct
|
|
|
|
list_for_each_entry_safe(table, nt, &afi->tables, list) {
|
|
list_for_each_entry(chain, &table->chains, list)
|
|
- nf_tables_unregister_hooks(net, table, chain,
|
|
- afi->nops);
|
|
+ nf_tables_unregister_hook(net, table, chain);
|
|
/* No packets are walking on these chains anymore. */
|
|
ctx.table = table;
|
|
list_for_each_entry(chain, &table->chains, list) {
|
|
--- a/net/netfilter/nf_tables_inet.c
|
|
+++ b/net/netfilter/nf_tables_inet.c
|
|
@@ -74,7 +74,6 @@ static struct nft_af_info nft_af_inet __
|
|
.family = NFPROTO_INET,
|
|
.nhooks = NF_INET_NUMHOOKS,
|
|
.owner = THIS_MODULE,
|
|
- .nops = 1,
|
|
.hooks = {
|
|
[NF_INET_LOCAL_IN] = nft_do_chain_inet,
|
|
[NF_INET_LOCAL_OUT] = nft_inet_output,
|
|
--- a/net/netfilter/nf_tables_netdev.c
|
|
+++ b/net/netfilter/nf_tables_netdev.c
|
|
@@ -43,7 +43,6 @@ static struct nft_af_info nft_af_netdev
|
|
.nhooks = NF_NETDEV_NUMHOOKS,
|
|
.owner = THIS_MODULE,
|
|
.flags = NFT_AF_NEEDS_DEV,
|
|
- .nops = 1,
|
|
.hooks = {
|
|
[NF_NETDEV_INGRESS] = nft_do_chain_netdev,
|
|
},
|
|
@@ -98,7 +97,7 @@ static void nft_netdev_event(unsigned lo
|
|
__nft_release_basechain(ctx);
|
|
break;
|
|
case NETDEV_CHANGENAME:
|
|
- if (dev->ifindex != basechain->ops[0].dev->ifindex)
|
|
+ if (dev->ifindex != basechain->ops.dev->ifindex)
|
|
return;
|
|
|
|
strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
|
|
--- a/net/netfilter/nft_compat.c
|
|
+++ b/net/netfilter/nft_compat.c
|
|
@@ -186,7 +186,7 @@ nft_target_set_tgchk_param(struct xt_tgc
|
|
if (nft_is_base_chain(ctx->chain)) {
|
|
const struct nft_base_chain *basechain =
|
|
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;
|
|
} else {
|
|
@@ -317,7 +317,7 @@ static int nft_target_validate(const str
|
|
if (nft_is_base_chain(ctx->chain)) {
|
|
const struct nft_base_chain *basechain =
|
|
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;
|
|
if (target->hooks && !(hook_mask & target->hooks))
|
|
@@ -414,7 +414,7 @@ nft_match_set_mtchk_param(struct xt_mtch
|
|
if (nft_is_base_chain(ctx->chain)) {
|
|
const struct nft_base_chain *basechain =
|
|
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;
|
|
} else {
|
|
@@ -565,7 +565,7 @@ static int nft_match_validate(const stru
|
|
if (nft_is_base_chain(ctx->chain)) {
|
|
const struct nft_base_chain *basechain =
|
|
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;
|
|
if (match->hooks && !(hook_mask & match->hooks))
|
|
|