* [PATCH nf-next,v2 1/6] netfilter: nf_tables: add NFTA_CHAIN_ID attribute
@ 2020-07-01 20:52 Pablo Neira Ayuso
2020-07-01 20:52 ` [PATCH nf-next,v2 2/6] netfilter: nf_tables: add NFTA_RULE_CHAIN_ID attribute Pablo Neira Ayuso
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2020-07-01 20:52 UTC (permalink / raw)
To: netfilter-devel
This netlink attribute allows you to refer to chains inside a
transaction as an alternative to the name and the handle. The chain
binding support requires this new chain ID approach.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes.
include/net/netfilter/nf_tables.h | 3 +++
include/uapi/linux/netfilter/nf_tables.h | 2 ++
net/netfilter/nf_tables_api.c | 15 ++++++++++++---
3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 6f0f6fca9ac3..3e5226684017 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1433,6 +1433,7 @@ struct nft_trans_chain {
char *name;
struct nft_stats __percpu *stats;
u8 policy;
+ u32 chain_id;
};
#define nft_trans_chain_update(trans) \
@@ -1443,6 +1444,8 @@ struct nft_trans_chain {
(((struct nft_trans_chain *)trans->data)->stats)
#define nft_trans_chain_policy(trans) \
(((struct nft_trans_chain *)trans->data)->policy)
+#define nft_trans_chain_id(trans) \
+ (((struct nft_trans_chain *)trans->data)->chain_id)
struct nft_trans_table {
bool update;
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 4565456c0ef4..477779595b78 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -196,6 +196,7 @@ enum nft_table_attributes {
* @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING)
* @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes)
* @NFTA_CHAIN_FLAGS: chain flags
+ * @NFTA_CHAIN_ID: uniquely identifies a chain in a transaction (NLA_U32)
*/
enum nft_chain_attributes {
NFTA_CHAIN_UNSPEC,
@@ -209,6 +210,7 @@ enum nft_chain_attributes {
NFTA_CHAIN_COUNTERS,
NFTA_CHAIN_PAD,
NFTA_CHAIN_FLAGS,
+ NFTA_CHAIN_ID,
__NFTA_CHAIN_MAX
};
#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 7647ecfa0d40..650ef0dd0773 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -280,9 +280,15 @@ static struct nft_trans *nft_trans_chain_add(struct nft_ctx *ctx, int msg_type)
if (trans == NULL)
return ERR_PTR(-ENOMEM);
- if (msg_type == NFT_MSG_NEWCHAIN)
+ if (msg_type == NFT_MSG_NEWCHAIN) {
nft_activate_next(ctx->net, ctx->chain);
+ if (ctx->nla[NFTA_CHAIN_ID]) {
+ nft_trans_chain_id(trans) =
+ ntohl(nla_get_be32(ctx->nla[NFTA_CHAIN_ID]));
+ }
+ }
+
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
return trans;
}
@@ -1274,6 +1280,7 @@ static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
.len = NFT_MODULE_AUTOLOAD_LIMIT },
[NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED },
[NFTA_CHAIN_FLAGS] = { .type = NLA_U32 },
+ [NFTA_CHAIN_ID] = { .type = NLA_U32 },
};
static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
@@ -2154,9 +2161,9 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u8 genmask = nft_genmask_next(net);
int family = nfmsg->nfgen_family;
+ struct nft_chain *chain = NULL;
const struct nlattr *attr;
struct nft_table *table;
- struct nft_chain *chain;
u8 policy = NF_ACCEPT;
struct nft_ctx ctx;
u64 handle = 0;
@@ -2181,7 +2188,7 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
return PTR_ERR(chain);
}
attr = nla[NFTA_CHAIN_HANDLE];
- } else {
+ } else if (nla[NFTA_CHAIN_NAME]) {
chain = nft_chain_lookup(net, table, attr, genmask);
if (IS_ERR(chain)) {
if (PTR_ERR(chain) != -ENOENT) {
@@ -2190,6 +2197,8 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
}
chain = NULL;
}
+ } else if (!nla[NFTA_CHAIN_ID]) {
+ return -EINVAL;
}
if (nla[NFTA_CHAIN_POLICY]) {
--
2.20.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH nf-next,v2 2/6] netfilter: nf_tables: add NFTA_RULE_CHAIN_ID attribute
2020-07-01 20:52 [PATCH nf-next,v2 1/6] netfilter: nf_tables: add NFTA_CHAIN_ID attribute Pablo Neira Ayuso
@ 2020-07-01 20:52 ` Pablo Neira Ayuso
2020-07-01 20:52 ` [PATCH nf-next,v2 3/6] netfilter: nf_tables: add NFTA_VERDICT_CHAIN_ID attribute Pablo Neira Ayuso
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2020-07-01 20:52 UTC (permalink / raw)
To: netfilter-devel
This new netlink attribute allows you to add rules to chains by the
chain ID.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes.
include/uapi/linux/netfilter/nf_tables.h | 1 +
net/netfilter/nf_tables_api.c | 36 +++++++++++++++++++++---
2 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 477779595b78..2304d1b7ba5e 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -240,6 +240,7 @@ enum nft_rule_attributes {
NFTA_RULE_PAD,
NFTA_RULE_ID,
NFTA_RULE_POSITION_ID,
+ NFTA_RULE_CHAIN_ID,
__NFTA_RULE_MAX
};
#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 650ef0dd0773..fbe8f9209813 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -2153,6 +2153,22 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
return err;
}
+static struct nft_chain *nft_chain_lookup_byid(const struct net *net,
+ const struct nlattr *nla)
+{
+ u32 id = ntohl(nla_get_be32(nla));
+ struct nft_trans *trans;
+
+ list_for_each_entry(trans, &net->nft.commit_list, list) {
+ struct nft_chain *chain = trans->ctx.chain;
+
+ if (trans->msg_type == NFT_MSG_NEWCHAIN &&
+ id == nft_trans_chain_id(trans))
+ return chain;
+ }
+ return ERR_PTR(-ENOENT);
+}
+
static int nf_tables_newchain(struct net *net, struct sock *nlsk,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[],
@@ -2633,6 +2649,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
.len = NFT_USERDATA_MAXLEN },
[NFTA_RULE_ID] = { .type = NLA_U32 },
[NFTA_RULE_POSITION_ID] = { .type = NLA_U32 },
+ [NFTA_RULE_CHAIN_ID] = { .type = NLA_U32 },
};
static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
@@ -3039,10 +3056,21 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
return PTR_ERR(table);
}
- chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN], genmask);
- if (IS_ERR(chain)) {
- NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
- return PTR_ERR(chain);
+ if (nla[NFTA_RULE_CHAIN]) {
+ chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN],
+ genmask);
+ if (IS_ERR(chain)) {
+ NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
+ return PTR_ERR(chain);
+ }
+ } else if (nla[NFTA_RULE_CHAIN_ID]) {
+ chain = nft_chain_lookup_byid(net, nla[NFTA_RULE_CHAIN_ID]);
+ if (IS_ERR(chain)) {
+ NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN_ID]);
+ return PTR_ERR(chain);
+ }
+ } else {
+ return -EINVAL;
}
if (nla[NFTA_RULE_HANDLE]) {
--
2.20.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH nf-next,v2 3/6] netfilter: nf_tables: add NFTA_VERDICT_CHAIN_ID attribute
2020-07-01 20:52 [PATCH nf-next,v2 1/6] netfilter: nf_tables: add NFTA_CHAIN_ID attribute Pablo Neira Ayuso
2020-07-01 20:52 ` [PATCH nf-next,v2 2/6] netfilter: nf_tables: add NFTA_RULE_CHAIN_ID attribute Pablo Neira Ayuso
@ 2020-07-01 20:52 ` Pablo Neira Ayuso
2020-07-01 20:52 ` [PATCH nf-next,v2 4/6] netfilter: nf_tables: expose enum nft_chain_flags through UAPI Pablo Neira Ayuso
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2020-07-01 20:52 UTC (permalink / raw)
To: netfilter-devel
This netlink attribute allows you to identify the chain to jump/goto by
means of the chain ID.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v3: no changes.
include/uapi/linux/netfilter/nf_tables.h | 2 ++
net/netfilter/nf_tables_api.c | 16 +++++++++++++---
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 2304d1b7ba5e..683e75126d68 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -471,11 +471,13 @@ enum nft_data_attributes {
*
* @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts)
* @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING)
+ * @NFTA_VERDICT_CHAIN_ID: jump target chain ID (NLA_U32)
*/
enum nft_verdict_attributes {
NFTA_VERDICT_UNSPEC,
NFTA_VERDICT_CODE,
NFTA_VERDICT_CHAIN,
+ NFTA_VERDICT_CHAIN_ID,
__NFTA_VERDICT_MAX
};
#define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index fbe8f9209813..9be978788aef 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -8242,6 +8242,7 @@ static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
[NFTA_VERDICT_CODE] = { .type = NLA_U32 },
[NFTA_VERDICT_CHAIN] = { .type = NLA_STRING,
.len = NFT_CHAIN_MAXNAMELEN - 1 },
+ [NFTA_VERDICT_CHAIN_ID] = { .type = NLA_U32 },
};
static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
@@ -8278,10 +8279,19 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
break;
case NFT_JUMP:
case NFT_GOTO:
- if (!tb[NFTA_VERDICT_CHAIN])
+ if (tb[NFTA_VERDICT_CHAIN]) {
+ chain = nft_chain_lookup(ctx->net, ctx->table,
+ tb[NFTA_VERDICT_CHAIN],
+ genmask);
+ } else if (tb[NFTA_VERDICT_CHAIN_ID]) {
+ chain = nft_chain_lookup_byid(ctx->net,
+ tb[NFTA_VERDICT_CHAIN_ID]);
+ if (chain->use != 0)
+ return -EBUSY;
+ } else {
return -EINVAL;
- chain = nft_chain_lookup(ctx->net, ctx->table,
- tb[NFTA_VERDICT_CHAIN], genmask);
+ }
+
if (IS_ERR(chain))
return PTR_ERR(chain);
if (nft_is_base_chain(chain))
--
2.20.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH nf-next,v2 4/6] netfilter: nf_tables: expose enum nft_chain_flags through UAPI
2020-07-01 20:52 [PATCH nf-next,v2 1/6] netfilter: nf_tables: add NFTA_CHAIN_ID attribute Pablo Neira Ayuso
2020-07-01 20:52 ` [PATCH nf-next,v2 2/6] netfilter: nf_tables: add NFTA_RULE_CHAIN_ID attribute Pablo Neira Ayuso
2020-07-01 20:52 ` [PATCH nf-next,v2 3/6] netfilter: nf_tables: add NFTA_VERDICT_CHAIN_ID attribute Pablo Neira Ayuso
@ 2020-07-01 20:52 ` Pablo Neira Ayuso
2020-07-01 20:53 ` [PATCH nf-next,v2 5/6] netfilter: nf_tables: add nft_chain_add() Pablo Neira Ayuso
2020-07-01 20:53 ` [PATCH nf-next,v2 6/6] netfilter: nf_tables: add NFT_CHAIN_BINDING Pablo Neira Ayuso
4 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2020-07-01 20:52 UTC (permalink / raw)
To: netfilter-devel
This enum definition was never exposed through UAPI. Rename
NFT_BASE_CHAIN to NFT_CHAIN_BASE for consistency.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes.
include/net/netfilter/nf_tables.h | 7 +------
include/uapi/linux/netfilter/nf_tables.h | 5 +++++
net/netfilter/nf_tables_api.c | 4 ++--
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 3e5226684017..6d1e7da6e00a 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -921,11 +921,6 @@ static inline void nft_set_elem_update_expr(const struct nft_set_ext *ext,
(expr) != (last); \
(expr) = nft_expr_next(expr))
-enum nft_chain_flags {
- NFT_BASE_CHAIN = 0x1,
- NFT_CHAIN_HW_OFFLOAD = 0x2,
-};
-
#define NFT_CHAIN_POLICY_UNSET U8_MAX
/**
@@ -1036,7 +1031,7 @@ static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chai
static inline bool nft_is_base_chain(const struct nft_chain *chain)
{
- return chain->flags & NFT_BASE_CHAIN;
+ return chain->flags & NFT_CHAIN_BASE;
}
int __nft_release_basechain(struct nft_ctx *ctx);
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 683e75126d68..2cf7cc3b50c1 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -184,6 +184,11 @@ enum nft_table_attributes {
};
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
+enum nft_chain_flags {
+ NFT_CHAIN_BASE = (1 << 0),
+ NFT_CHAIN_HW_OFFLOAD = (1 << 1),
+};
+
/**
* enum nft_chain_attributes - nf_tables chain netlink attributes
*
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 9be978788aef..03fc2538e7c9 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -1903,7 +1903,7 @@ static int nft_basechain_init(struct nft_base_chain *basechain, u8 family,
nft_basechain_hook_init(&basechain->ops, family, hook, chain);
}
- chain->flags |= NFT_BASE_CHAIN | flags;
+ chain->flags |= NFT_CHAIN_BASE | flags;
basechain->policy = NF_ACCEPT;
if (chain->flags & NFT_CHAIN_HW_OFFLOAD &&
nft_chain_offload_priority(basechain) < 0)
@@ -2255,7 +2255,7 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
if (nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP;
- flags |= chain->flags & NFT_BASE_CHAIN;
+ flags |= chain->flags & NFT_CHAIN_BASE;
return nf_tables_updchain(&ctx, genmask, policy, flags);
}
--
2.20.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH nf-next,v2 5/6] netfilter: nf_tables: add nft_chain_add()
2020-07-01 20:52 [PATCH nf-next,v2 1/6] netfilter: nf_tables: add NFTA_CHAIN_ID attribute Pablo Neira Ayuso
` (2 preceding siblings ...)
2020-07-01 20:52 ` [PATCH nf-next,v2 4/6] netfilter: nf_tables: expose enum nft_chain_flags through UAPI Pablo Neira Ayuso
@ 2020-07-01 20:53 ` Pablo Neira Ayuso
2020-07-01 20:53 ` [PATCH nf-next,v2 6/6] netfilter: nf_tables: add NFT_CHAIN_BINDING Pablo Neira Ayuso
4 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2020-07-01 20:53 UTC (permalink / raw)
To: netfilter-devel
This patch adds a helper function to add the chain to the hashtable and
the chain list.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes:
net/netfilter/nf_tables_api.c | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 03fc2538e7c9..572f049d7de4 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -1914,6 +1914,20 @@ static int nft_basechain_init(struct nft_base_chain *basechain, u8 family,
return 0;
}
+static int nft_chain_add(struct nft_table *table, struct nft_chain *chain)
+{
+ int err;
+
+ err = rhltable_insert_key(&table->chains_ht, chain->name,
+ &chain->rhlhead, nft_chain_ht_params);
+ if (err)
+ return err;
+
+ list_add_tail_rcu(&chain->list, &table->chains);
+
+ return 0;
+}
+
static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
u8 policy, u32 flags)
{
@@ -1991,16 +2005,9 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
if (err < 0)
goto err1;
- err = rhltable_insert_key(&table->chains_ht, chain->name,
- &chain->rhlhead, nft_chain_ht_params);
- if (err)
- goto err2;
-
trans = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN);
if (IS_ERR(trans)) {
err = PTR_ERR(trans);
- rhltable_remove(&table->chains_ht, &chain->rhlhead,
- nft_chain_ht_params);
goto err2;
}
@@ -2008,8 +2015,13 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
if (nft_is_base_chain(chain))
nft_trans_chain_policy(trans) = policy;
+ err = nft_chain_add(table, chain);
+ if (err < 0) {
+ nft_trans_destroy(trans);
+ goto err2;
+ }
+
table->use++;
- list_add_tail_rcu(&chain->list, &table->chains);
return 0;
err2:
--
2.20.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH nf-next,v2 6/6] netfilter: nf_tables: add NFT_CHAIN_BINDING
2020-07-01 20:52 [PATCH nf-next,v2 1/6] netfilter: nf_tables: add NFTA_CHAIN_ID attribute Pablo Neira Ayuso
` (3 preceding siblings ...)
2020-07-01 20:53 ` [PATCH nf-next,v2 5/6] netfilter: nf_tables: add nft_chain_add() Pablo Neira Ayuso
@ 2020-07-01 20:53 ` Pablo Neira Ayuso
4 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2020-07-01 20:53 UTC (permalink / raw)
To: netfilter-devel
This new chain flag specifies that:
* the kernel dynamically allocates the chain name, if no chain name
is specified.
* If the immediate expression that refers to this chain is removed,
then this bound chain (and its content) is destroyed.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: fix NFTA_CHAIN_FLAGS netlink dumping.
include/net/netfilter/nf_tables.h | 13 +++-
include/uapi/linux/netfilter/nf_tables.h | 1 +
net/netfilter/nf_tables_api.c | 78 ++++++++++++++++++++----
net/netfilter/nft_immediate.c | 51 ++++++++++++++++
4 files changed, 130 insertions(+), 13 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 6d1e7da6e00a..0ebbe000bb0a 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -899,6 +899,8 @@ static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule)
return (void *)&rule->data[rule->dlen];
}
+void nf_tables_rule_destroy(const struct nft_ctx *ctx, struct nft_rule *rule);
+
static inline void nft_set_elem_update_expr(const struct nft_set_ext *ext,
struct nft_regs *regs,
const struct nft_pktinfo *pkt)
@@ -944,7 +946,8 @@ struct nft_chain {
struct nft_table *table;
u64 handle;
u32 use;
- u8 flags:6,
+ u8 flags:5,
+ bound:1,
genmask:2;
char *name;
@@ -989,6 +992,14 @@ int nft_chain_validate_dependency(const struct nft_chain *chain,
int nft_chain_validate_hooks(const struct nft_chain *chain,
unsigned int hook_flags);
+static inline bool nft_chain_is_bound(struct nft_chain *chain)
+{
+ return (chain->flags & NFT_CHAIN_BINDING) && chain->bound;
+}
+
+void nft_chain_del(struct nft_chain *chain);
+void nf_tables_chain_destroy(struct nft_ctx *ctx);
+
struct nft_stats {
u64 bytes;
u64 pkts;
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 2cf7cc3b50c1..e00b4ae6174e 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -187,6 +187,7 @@ enum nft_table_attributes {
enum nft_chain_flags {
NFT_CHAIN_BASE = (1 << 0),
NFT_CHAIN_HW_OFFLOAD = (1 << 1),
+ NFT_CHAIN_BINDING = (1 << 2),
};
/**
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 572f049d7de4..06f652fe9fd5 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -1098,6 +1098,9 @@ static int nft_flush_table(struct nft_ctx *ctx)
if (!nft_is_active_next(ctx->net, chain))
continue;
+ if (nft_chain_is_bound(chain))
+ continue;
+
ctx->chain = chain;
err = nft_delchain(ctx);
@@ -1413,13 +1416,12 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
lockdep_commit_lock_is_held(net));
if (nft_dump_stats(skb, stats))
goto nla_put_failure;
-
- if ((chain->flags & NFT_CHAIN_HW_OFFLOAD) &&
- nla_put_be32(skb, NFTA_CHAIN_FLAGS,
- htonl(NFT_CHAIN_HW_OFFLOAD)))
- goto nla_put_failure;
}
+ if (chain->flags &&
+ nla_put_be32(skb, NFTA_CHAIN_FLAGS, htonl(chain->flags)))
+ goto nla_put_failure;
+
if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
goto nla_put_failure;
@@ -1621,7 +1623,7 @@ static void nf_tables_chain_free_chain_rules(struct nft_chain *chain)
kvfree(chain->rules_next);
}
-static void nf_tables_chain_destroy(struct nft_ctx *ctx)
+void nf_tables_chain_destroy(struct nft_ctx *ctx)
{
struct nft_chain *chain = ctx->chain;
struct nft_hook *hook, *next;
@@ -1928,6 +1930,8 @@ static int nft_chain_add(struct nft_table *table, struct nft_chain *chain)
return 0;
}
+static u64 chain_id;
+
static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
u8 policy, u32 flags)
{
@@ -1936,6 +1940,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
struct nft_base_chain *basechain;
struct nft_stats __percpu *stats;
struct net *net = ctx->net;
+ char name[NFT_NAME_MAXLEN];
struct nft_trans *trans;
struct nft_chain *chain;
struct nft_rule **rules;
@@ -1947,6 +1952,9 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
if (nla[NFTA_CHAIN_HOOK]) {
struct nft_chain_hook hook;
+ if (flags & NFT_CHAIN_BINDING)
+ return -EOPNOTSUPP;
+
err = nft_chain_parse_hook(net, nla, &hook, family, true);
if (err < 0)
return err;
@@ -1976,16 +1984,33 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
return err;
}
} else {
+ if (flags & NFT_CHAIN_BASE)
+ return -EINVAL;
+ if (flags & NFT_CHAIN_HW_OFFLOAD)
+ return -EOPNOTSUPP;
+
chain = kzalloc(sizeof(*chain), GFP_KERNEL);
if (chain == NULL)
return -ENOMEM;
+
+ chain->flags = flags;
}
ctx->chain = chain;
INIT_LIST_HEAD(&chain->rules);
chain->handle = nf_tables_alloc_handle(table);
chain->table = table;
- chain->name = nla_strdup(nla[NFTA_CHAIN_NAME], GFP_KERNEL);
+
+ if (nla[NFTA_CHAIN_NAME]) {
+ chain->name = nla_strdup(nla[NFTA_CHAIN_NAME], GFP_KERNEL);
+ } else {
+ if (!(flags & NFT_CHAIN_BINDING))
+ return -EINVAL;
+
+ snprintf(name, sizeof(name), "__chain%llu", ++chain_id);
+ chain->name = kstrdup(name, GFP_KERNEL);
+ }
+
if (!chain->name) {
err = -ENOMEM;
goto err1;
@@ -2958,8 +2983,7 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
return err;
}
-static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
- struct nft_rule *rule)
+void nf_tables_rule_destroy(const struct nft_ctx *ctx, struct nft_rule *rule)
{
struct nft_expr *expr, *next;
@@ -5330,11 +5354,24 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
*/
void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
{
+ struct nft_chain *chain;
+ struct nft_rule *rule;
+
if (type == NFT_DATA_VERDICT) {
switch (data->verdict.code) {
case NFT_JUMP:
case NFT_GOTO:
- data->verdict.chain->use++;
+ chain = data->verdict.chain;
+ chain->use++;
+
+ if (!nft_chain_is_bound(chain))
+ break;
+
+ chain->table->use++;
+ list_for_each_entry(rule, &chain->rules, list)
+ chain->use++;
+
+ nft_chain_add(chain->table, chain);
break;
}
}
@@ -7474,7 +7511,7 @@ static void nft_obj_del(struct nft_object *obj)
list_del_rcu(&obj->list);
}
-static void nft_chain_del(struct nft_chain *chain)
+void nft_chain_del(struct nft_chain *chain)
{
struct nft_table *table = chain->table;
@@ -7825,6 +7862,10 @@ static int __nf_tables_abort(struct net *net, bool autoload)
kfree(nft_trans_chain_name(trans));
nft_trans_destroy(trans);
} else {
+ if (nft_chain_is_bound(trans->ctx.chain)) {
+ nft_trans_destroy(trans);
+ break;
+ }
trans->ctx.table->use--;
nft_chain_del(trans->ctx.chain);
nf_tables_unregister_hook(trans->ctx.net,
@@ -8321,10 +8362,23 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
static void nft_verdict_uninit(const struct nft_data *data)
{
+ struct nft_chain *chain;
+ struct nft_rule *rule;
+
switch (data->verdict.code) {
case NFT_JUMP:
case NFT_GOTO:
- data->verdict.chain->use--;
+ chain = data->verdict.chain;
+ chain->use--;
+
+ if (!nft_chain_is_bound(chain))
+ break;
+
+ chain->table->use--;
+ list_for_each_entry(rule, &chain->rules, list)
+ chain->use--;
+
+ nft_chain_del(chain);
break;
}
}
diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c
index c7f0ef73d939..255603df1789 100644
--- a/net/netfilter/nft_immediate.c
+++ b/net/netfilter/nft_immediate.c
@@ -54,6 +54,23 @@ static int nft_immediate_init(const struct nft_ctx *ctx,
if (err < 0)
goto err1;
+ if (priv->dreg == NFT_REG_VERDICT) {
+ struct nft_chain *chain = priv->data.verdict.chain;
+
+ switch (priv->data.verdict.code) {
+ case NFT_JUMP:
+ case NFT_GOTO:
+ if (nft_chain_is_bound(chain)) {
+ err = -EBUSY;
+ goto err1;
+ }
+ chain->bound = true;
+ break;
+ default:
+ break;
+ }
+ }
+
return 0;
err1:
@@ -81,6 +98,39 @@ static void nft_immediate_deactivate(const struct nft_ctx *ctx,
return nft_data_release(&priv->data, nft_dreg_to_type(priv->dreg));
}
+static void nft_immediate_destroy(const struct nft_ctx *ctx,
+ const struct nft_expr *expr)
+{
+ const struct nft_immediate_expr *priv = nft_expr_priv(expr);
+ const struct nft_data *data = &priv->data;
+ struct nft_ctx chain_ctx;
+ struct nft_chain *chain;
+ struct nft_rule *rule;
+
+ if (priv->dreg != NFT_REG_VERDICT)
+ return;
+
+ switch (data->verdict.code) {
+ case NFT_JUMP:
+ case NFT_GOTO:
+ chain = data->verdict.chain;
+
+ if (!nft_chain_is_bound(chain))
+ break;
+
+ chain_ctx = *ctx;
+ chain_ctx.chain = chain;
+
+ list_for_each_entry(rule, &chain->rules, list)
+ nf_tables_rule_destroy(&chain_ctx, rule);
+
+ nf_tables_chain_destroy(&chain_ctx);
+ break;
+ default:
+ break;
+ }
+}
+
static int nft_immediate_dump(struct sk_buff *skb, const struct nft_expr *expr)
{
const struct nft_immediate_expr *priv = nft_expr_priv(expr);
@@ -170,6 +220,7 @@ static const struct nft_expr_ops nft_imm_ops = {
.init = nft_immediate_init,
.activate = nft_immediate_activate,
.deactivate = nft_immediate_deactivate,
+ .destroy = nft_immediate_destroy,
.dump = nft_immediate_dump,
.validate = nft_immediate_validate,
.offload = nft_immediate_offload,
--
2.20.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2020-07-01 20:53 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-01 20:52 [PATCH nf-next,v2 1/6] netfilter: nf_tables: add NFTA_CHAIN_ID attribute Pablo Neira Ayuso
2020-07-01 20:52 ` [PATCH nf-next,v2 2/6] netfilter: nf_tables: add NFTA_RULE_CHAIN_ID attribute Pablo Neira Ayuso
2020-07-01 20:52 ` [PATCH nf-next,v2 3/6] netfilter: nf_tables: add NFTA_VERDICT_CHAIN_ID attribute Pablo Neira Ayuso
2020-07-01 20:52 ` [PATCH nf-next,v2 4/6] netfilter: nf_tables: expose enum nft_chain_flags through UAPI Pablo Neira Ayuso
2020-07-01 20:53 ` [PATCH nf-next,v2 5/6] netfilter: nf_tables: add nft_chain_add() Pablo Neira Ayuso
2020-07-01 20:53 ` [PATCH nf-next,v2 6/6] netfilter: nf_tables: add NFT_CHAIN_BINDING Pablo Neira Ayuso
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).