* [PATCH nf-next 1/6] netfilter: nf_tables: add generic macros to check for generation mask
@ 2016-06-22 11:14 Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 2/6] netfilter: nf_tables: add generation mask to tables Pablo Neira Ayuso
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Pablo Neira Ayuso @ 2016-06-22 11:14 UTC (permalink / raw)
To: netfilter-devel
Thus, we can reuse these to check the genmask of any object type, not
only rules. This is required now that tables, chain and sets will get a
generation mask field too in follow up patches.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_tables.h | 24 ++++++++++++++++++++
net/netfilter/nf_tables_api.c | 46 +++++++--------------------------------
2 files changed, 32 insertions(+), 38 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index f7c291f..6b7ce3a 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -971,6 +971,30 @@ static inline u8 nft_genmask_cur(const struct net *net)
#define NFT_GENMASK_ANY ((1 << 0) | (1 << 1))
/*
+ * Generic transaction helpers
+ */
+
+/* Check if this object is currently active. */
+#define nft_is_active(__net, __obj) \
+ (((__obj)->genmask & nft_genmask_cur(__net)) == 0)
+
+/* Check if this object is active in the next generation. */
+#define nft_is_active_next(__net, __obj) \
+ (((__obj)->genmask & nft_genmask_next(__net)) == 0)
+
+/* This object becomes active in the next generation. */
+#define nft_activate_next(__net, __obj) \
+ (__obj)->genmask = nft_genmask_cur(__net)
+
+/* This object becomes inactive in the next generation. */
+#define nft_deactivate_next(__net, __obj) \
+ (__obj)->genmask = nft_genmask_next(__net)
+
+/* After committing the ruleset, clear the stale generation bit. */
+#define nft_clear(__net, __obj) \
+ (__obj)->genmask &= ~nft_genmask_next(__net)
+
+/*
* Set element transaction helpers
*/
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 2c88187..bae7d67 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -234,42 +234,12 @@ static int nft_delchain(struct nft_ctx *ctx)
return err;
}
-static inline bool
-nft_rule_is_active(struct net *net, const struct nft_rule *rule)
-{
- return (rule->genmask & nft_genmask_cur(net)) == 0;
-}
-
-static inline int
-nft_rule_is_active_next(struct net *net, const struct nft_rule *rule)
-{
- return (rule->genmask & nft_genmask_next(net)) == 0;
-}
-
-static inline void
-nft_rule_activate_next(struct net *net, struct nft_rule *rule)
-{
- /* Now inactive, will be active in the future */
- rule->genmask = nft_genmask_cur(net);
-}
-
-static inline void
-nft_rule_deactivate_next(struct net *net, struct nft_rule *rule)
-{
- rule->genmask = nft_genmask_next(net);
-}
-
-static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
-{
- rule->genmask &= ~nft_genmask_next(net);
-}
-
static int
nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule)
{
/* You cannot delete the same rule twice */
- if (nft_rule_is_active_next(ctx->net, rule)) {
- nft_rule_deactivate_next(ctx->net, rule);
+ if (nft_is_active_next(ctx->net, rule)) {
+ nft_deactivate_next(ctx->net, rule);
ctx->chain->use--;
return 0;
}
@@ -1898,7 +1868,7 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
list_for_each_entry_rcu(table, &afi->tables, list) {
list_for_each_entry_rcu(chain, &table->chains, list) {
list_for_each_entry_rcu(rule, &chain->rules, list) {
- if (!nft_rule_is_active(net, rule))
+ if (!nft_is_active(net, rule))
goto cont;
if (idx < s_idx)
goto cont;
@@ -2102,7 +2072,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
if (rule == NULL)
goto err1;
- nft_rule_activate_next(net, rule);
+ nft_activate_next(net, rule);
rule->handle = handle;
rule->dlen = size;
@@ -2124,14 +2094,14 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
}
if (nlh->nlmsg_flags & NLM_F_REPLACE) {
- if (nft_rule_is_active_next(net, old_rule)) {
+ if (nft_is_active_next(net, old_rule)) {
trans = nft_trans_rule_add(&ctx, NFT_MSG_DELRULE,
old_rule);
if (trans == NULL) {
err = -ENOMEM;
goto err2;
}
- nft_rule_deactivate_next(net, old_rule);
+ nft_deactivate_next(net, old_rule);
chain->use--;
list_add_tail_rcu(&rule->list, &old_rule->list);
} else {
@@ -3979,7 +3949,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
trans->ctx.afi->nops);
break;
case NFT_MSG_NEWRULE:
- nft_rule_clear(trans->ctx.net, nft_trans_rule(trans));
+ nft_clear(trans->ctx.net, nft_trans_rule(trans));
nf_tables_rule_notify(&trans->ctx,
nft_trans_rule(trans),
NFT_MSG_NEWRULE);
@@ -4115,7 +4085,7 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
break;
case NFT_MSG_DELRULE:
trans->ctx.chain->use++;
- nft_rule_clear(trans->ctx.net, nft_trans_rule(trans));
+ nft_clear(trans->ctx.net, nft_trans_rule(trans));
nft_trans_destroy(trans);
break;
case NFT_MSG_NEWSET:
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH nf-next 2/6] netfilter: nf_tables: add generation mask to tables
2016-06-22 11:14 [PATCH nf-next 1/6] netfilter: nf_tables: add generic macros to check for generation mask Pablo Neira Ayuso
@ 2016-06-22 11:14 ` Pablo Neira Ayuso
2016-06-22 11:50 ` Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 3/6] netfilter: nf_tables: add generation mask to chains Pablo Neira Ayuso
` (3 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Pablo Neira Ayuso @ 2016-06-22 11:14 UTC (permalink / raw)
To: netfilter-devel
This patch addresses two problems:
1) The netlink dump is inconsistent when interfering with an ongoing
transaction update for several reasons:
1.a) We don't honor the internal NFT_TABLE_INACTIVE flag, and we should
be skipping these inactive objects in the dump.
1.b) We perform speculative deletion during the preparation phase, that
may result in skipping active objects.
1.c) The listing order changes, which generates noise when tracking
incremental ruleset update via tools like git or our own
testsuite.
2) We don't allow adding and deleting object a given object X in the
same batch.
In order to resolve these problems:
1) If the user requests a deletion, the object becomes inactive in the
next generation. Then, ignore objects that scheduled to be deleted
from the lookup path, as they will be effectively removed in the
next generation.
2) From the get/dump path, if the object is not currently active, we
skip it.
3) Support 'add X -> delete X -> add X' sequences from a transaction,
they are valid since robot may trigger these kind of incremental
updates.
After this update, we obtain a consistent list as long as we stay
in the same generation. The userspace side can detect interferences
through the generation counter so it can restart the dumping.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_tables.h | 6 ++-
net/netfilter/nf_tables_api.c | 101 +++++++++++++++++++++-----------------
2 files changed, 62 insertions(+), 45 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 6b7ce3a..5b802f8 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -839,6 +839,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);
* @hgenerator: handle generator state
* @use: number of chain references to this table
* @flags: table flag (see enum nft_table_flags)
+ * @genmask: generation mask
* @name: name of the table
*/
struct nft_table {
@@ -847,7 +848,8 @@ struct nft_table {
struct list_head sets;
u64 hgenerator;
u32 use;
- u16 flags;
+ u16 flags:14,
+ genmask:2;
char name[NFT_TABLE_MAXNAMELEN];
};
@@ -993,6 +995,8 @@ static inline u8 nft_genmask_cur(const struct net *net)
/* After committing the ruleset, clear the stale generation bit. */
#define nft_clear(__net, __obj) \
(__obj)->genmask &= ~nft_genmask_next(__net)
+#define nft_active_genmask(__obj, __genmask) \
+ !((__obj)->genmask & __genmask)
/*
* Set element transaction helpers
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index bae7d67..4cdc591 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -175,9 +175,6 @@ static void nf_tables_unregister_hooks(const struct nft_table *table,
nft_unregister_basechain(nft_base_chain(chain), hook_nops);
}
-/* Internal table flags */
-#define NFT_TABLE_INACTIVE (1 << 15)
-
static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
{
struct nft_trans *trans;
@@ -187,7 +184,7 @@ static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
return -ENOMEM;
if (msg_type == NFT_MSG_NEWTABLE)
- ctx->table->flags |= NFT_TABLE_INACTIVE;
+ nft_activate_next(ctx->net, ctx->table);
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
return 0;
@@ -201,7 +198,7 @@ static int nft_deltable(struct nft_ctx *ctx)
if (err < 0)
return err;
- list_del_rcu(&ctx->table->list);
+ nft_deactivate_next(ctx->net, ctx->table);
return err;
}
@@ -334,26 +331,29 @@ static int nft_delset(struct nft_ctx *ctx, struct nft_set *set)
*/
static struct nft_table *nft_table_lookup(const struct nft_af_info *afi,
- const struct nlattr *nla)
+ const struct nlattr *nla,
+ u8 genmask)
{
struct nft_table *table;
list_for_each_entry(table, &afi->tables, list) {
- if (!nla_strcmp(nla, table->name))
+ if (!nla_strcmp(nla, table->name) &&
+ nft_active_genmask(table, genmask))
return table;
}
return NULL;
}
static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi,
- const struct nlattr *nla)
+ const struct nlattr *nla,
+ u8 genmask)
{
struct nft_table *table;
if (nla == NULL)
return ERR_PTR(-EINVAL);
- table = nft_table_lookup(afi, nla);
+ table = nft_table_lookup(afi, nla, genmask);
if (table != NULL)
return table;
@@ -494,6 +494,8 @@ static int nf_tables_dump_tables(struct sk_buff *skb,
if (idx > s_idx)
memset(&cb->args[1], 0,
sizeof(cb->args) - sizeof(cb->args[0]));
+ if (!nft_is_active(net, table))
+ continue;
if (nf_tables_fill_table_info(skb, net,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
@@ -518,6 +520,7 @@ static int nf_tables_gettable(struct net *net, struct sock *nlsk,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u8 genmask = nft_genmask_cur(net);
const struct nft_af_info *afi;
const struct nft_table *table;
struct sk_buff *skb2;
@@ -535,11 +538,9 @@ static int nf_tables_gettable(struct net *net, struct sock *nlsk,
if (IS_ERR(afi))
return PTR_ERR(afi);
- table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
+ table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME], genmask);
if (IS_ERR(table))
return PTR_ERR(table);
- if (table->flags & NFT_TABLE_INACTIVE)
- return -ENOENT;
skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb2)
@@ -648,6 +649,7 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u8 genmask = nft_genmask_next(net);
const struct nlattr *name;
struct nft_af_info *afi;
struct nft_table *table;
@@ -661,7 +663,7 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
return PTR_ERR(afi);
name = nla[NFTA_TABLE_NAME];
- table = nf_tables_table_lookup(afi, name);
+ table = nf_tables_table_lookup(afi, name, genmask);
if (IS_ERR(table)) {
if (PTR_ERR(table) != -ENOENT)
return PTR_ERR(table);
@@ -669,8 +671,6 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
}
if (table != NULL) {
- if (table->flags & NFT_TABLE_INACTIVE)
- return -ENOENT;
if (nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST;
if (nlh->nlmsg_flags & NLM_F_REPLACE)
@@ -765,6 +765,9 @@ static int nft_flush(struct nft_ctx *ctx, int family)
ctx->afi = afi;
list_for_each_entry_safe(table, nt, &afi->tables, list) {
+ if (!nft_is_active_next(ctx->net, table))
+ continue;
+
if (nla[NFTA_TABLE_NAME] &&
nla_strcmp(nla[NFTA_TABLE_NAME], table->name) != 0)
continue;
@@ -785,6 +788,7 @@ static int nf_tables_deltable(struct net *net, struct sock *nlsk,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u8 genmask = nft_genmask_next(net);
struct nft_af_info *afi;
struct nft_table *table;
int family = nfmsg->nfgen_family;
@@ -798,7 +802,7 @@ static int nf_tables_deltable(struct net *net, struct sock *nlsk,
if (IS_ERR(afi))
return PTR_ERR(afi);
- table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
+ table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME], genmask);
if (IS_ERR(table))
return PTR_ERR(table);
@@ -1074,6 +1078,7 @@ static int nf_tables_getchain(struct net *net, struct sock *nlsk,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u8 genmask = nft_genmask_cur(net);
const struct nft_af_info *afi;
const struct nft_table *table;
const struct nft_chain *chain;
@@ -1092,11 +1097,9 @@ static int nf_tables_getchain(struct net *net, struct sock *nlsk,
if (IS_ERR(afi))
return PTR_ERR(afi);
- table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
+ table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE], genmask);
if (IS_ERR(table))
return PTR_ERR(table);
- if (table->flags & NFT_TABLE_INACTIVE)
- return -ENOENT;
chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
if (IS_ERR(chain))
@@ -1201,6 +1204,7 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
struct nft_chain *chain;
struct nft_base_chain *basechain = NULL;
struct nlattr *ha[NFTA_HOOK_MAX + 1];
+ u8 genmask = nft_genmask_next(net);
int family = nfmsg->nfgen_family;
struct net_device *dev = NULL;
u8 policy = NF_ACCEPT;
@@ -1217,7 +1221,7 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
if (IS_ERR(afi))
return PTR_ERR(afi);
- table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
+ table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE], genmask);
if (IS_ERR(table))
return PTR_ERR(table);
@@ -1449,6 +1453,7 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u8 genmask = nft_genmask_next(net);
struct nft_af_info *afi;
struct nft_table *table;
struct nft_chain *chain;
@@ -1459,7 +1464,7 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk,
if (IS_ERR(afi))
return PTR_ERR(afi);
- table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
+ table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE], genmask);
if (IS_ERR(table))
return PTR_ERR(table);
@@ -1901,6 +1906,7 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u8 genmask = nft_genmask_cur(net);
const struct nft_af_info *afi;
const struct nft_table *table;
const struct nft_chain *chain;
@@ -1920,11 +1926,9 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
if (IS_ERR(afi))
return PTR_ERR(afi);
- table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
+ table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE], genmask);
if (IS_ERR(table))
return PTR_ERR(table);
- if (table->flags & NFT_TABLE_INACTIVE)
- return -ENOENT;
chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
if (IS_ERR(chain))
@@ -1979,6 +1983,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u8 genmask = nft_genmask_next(net);
struct nft_af_info *afi;
struct nft_table *table;
struct nft_chain *chain;
@@ -1999,7 +2004,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
if (IS_ERR(afi))
return PTR_ERR(afi);
- table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
+ table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE], genmask);
if (IS_ERR(table))
return PTR_ERR(table);
@@ -2144,6 +2149,7 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u8 genmask = nft_genmask_next(net);
struct nft_af_info *afi;
struct nft_table *table;
struct nft_chain *chain = NULL;
@@ -2155,7 +2161,7 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
if (IS_ERR(afi))
return PTR_ERR(afi);
- table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
+ table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE], genmask);
if (IS_ERR(table))
return PTR_ERR(table);
@@ -2309,7 +2315,8 @@ static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
const struct sk_buff *skb,
const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
+ const struct nlattr * const nla[],
+ u8 genmask)
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nft_af_info *afi = NULL;
@@ -2325,7 +2332,8 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
if (afi == NULL)
return -EAFNOSUPPORT;
- table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
+ table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE],
+ genmask);
if (IS_ERR(table))
return PTR_ERR(table);
}
@@ -2586,6 +2594,7 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
+ u8 genmask = nft_genmask_cur(net);
const struct nft_set *set;
struct nft_ctx ctx;
struct sk_buff *skb2;
@@ -2593,7 +2602,7 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
int err;
/* Verify existence before starting dump */
- err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla);
+ err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla, genmask);
if (err < 0)
return err;
@@ -2663,6 +2672,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u8 genmask = nft_genmask_next(net);
const struct nft_set_ops *ops;
struct nft_af_info *afi;
struct nft_table *table;
@@ -2760,7 +2770,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
if (IS_ERR(afi))
return PTR_ERR(afi);
- table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
+ table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE], genmask);
if (IS_ERR(table))
return PTR_ERR(table);
@@ -2865,6 +2875,7 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u8 genmask = nft_genmask_next(net);
struct nft_set *set;
struct nft_ctx ctx;
int err;
@@ -2874,7 +2885,7 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
if (nla[NFTA_SET_TABLE] == NULL)
return -EINVAL;
- err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla);
+ err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla, genmask);
if (err < 0)
return err;
@@ -2999,7 +3010,8 @@ static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX +
static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
const struct sk_buff *skb,
const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
+ const struct nlattr * const nla[],
+ u8 genmask)
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nft_af_info *afi;
@@ -3009,7 +3021,8 @@ static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
if (IS_ERR(afi))
return PTR_ERR(afi);
- table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
+ table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE],
+ genmask);
if (IS_ERR(table))
return PTR_ERR(table);
@@ -3106,6 +3119,7 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = sock_net(skb->sk);
+ u8 genmask = nft_genmask_cur(net);
const struct nft_set *set;
struct nft_set_dump_args args;
struct nft_ctx ctx;
@@ -3122,11 +3136,9 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
return err;
err = nft_ctx_init_from_elemattr(&ctx, net, cb->skb, cb->nlh,
- (void *)nla);
+ (void *)nla, genmask);
if (err < 0)
return err;
- if (ctx.table->flags & NFT_TABLE_INACTIVE)
- return -ENOENT;
set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
if (IS_ERR(set))
@@ -3186,15 +3198,14 @@ static int nf_tables_getsetelem(struct net *net, struct sock *nlsk,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
+ u8 genmask = nft_genmask_cur(net);
const struct nft_set *set;
struct nft_ctx ctx;
int err;
- err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
+ err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, genmask);
if (err < 0)
return err;
- if (ctx.table->flags & NFT_TABLE_INACTIVE)
- return -ENOENT;
set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
if (IS_ERR(set))
@@ -3518,6 +3529,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
+ u8 genmask = nft_genmask_next(net);
const struct nlattr *attr;
struct nft_set *set;
struct nft_ctx ctx;
@@ -3526,7 +3538,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
return -EINVAL;
- err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
+ err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, genmask);
if (err < 0)
return err;
@@ -3640,6 +3652,7 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
+ u8 genmask = nft_genmask_next(net);
const struct nlattr *attr;
struct nft_set *set;
struct nft_ctx ctx;
@@ -3648,7 +3661,7 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
return -EINVAL;
- err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
+ err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, genmask);
if (err < 0)
return err;
@@ -3925,12 +3938,13 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
}
} else {
- trans->ctx.table->flags &= ~NFT_TABLE_INACTIVE;
+ nft_clear(net, trans->ctx.table);
}
nf_tables_table_notify(&trans->ctx, NFT_MSG_NEWTABLE);
nft_trans_destroy(trans);
break;
case NFT_MSG_DELTABLE:
+ list_del_rcu(&trans->ctx.table->list);
nf_tables_table_notify(&trans->ctx, NFT_MSG_DELTABLE);
break;
case NFT_MSG_NEWCHAIN:
@@ -4056,8 +4070,7 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
}
break;
case NFT_MSG_DELTABLE:
- list_add_tail_rcu(&trans->ctx.table->list,
- &trans->ctx.afi->tables);
+ nft_clear(trans->ctx.net, trans->ctx.table);
nft_trans_destroy(trans);
break;
case NFT_MSG_NEWCHAIN:
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH nf-next 3/6] netfilter: nf_tables: add generation mask to chains
2016-06-22 11:14 [PATCH nf-next 1/6] netfilter: nf_tables: add generic macros to check for generation mask Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 2/6] netfilter: nf_tables: add generation mask to tables Pablo Neira Ayuso
@ 2016-06-22 11:14 ` Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 4/6] netfilter: nf_tables: add generation mask to sets Pablo Neira Ayuso
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Pablo Neira Ayuso @ 2016-06-22 11:14 UTC (permalink / raw)
To: netfilter-devel
Similar to ("netfilter: nf_tables: add generation mask to tables").
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_tables.h | 4 +-
net/netfilter/nf_tables_api.c | 89 +++++++++++++++++++++++++--------------
2 files changed, 60 insertions(+), 33 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 5b802f8..2e97a24 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -733,7 +733,6 @@ static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule)
enum nft_chain_flags {
NFT_BASE_CHAIN = 0x1,
- NFT_CHAIN_INACTIVE = 0x2,
};
/**
@@ -755,7 +754,8 @@ struct nft_chain {
u64 handle;
u32 use;
u16 level;
- u8 flags;
+ u8 flags:6,
+ genmask:2;
char name[NFT_CHAIN_MAXNAMELEN];
};
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 4cdc591..0581978 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -211,7 +211,7 @@ static int nft_trans_chain_add(struct nft_ctx *ctx, int msg_type)
return -ENOMEM;
if (msg_type == NFT_MSG_NEWCHAIN)
- ctx->chain->flags |= NFT_CHAIN_INACTIVE;
+ nft_activate_next(ctx->net, ctx->chain);
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
return 0;
@@ -226,7 +226,7 @@ static int nft_delchain(struct nft_ctx *ctx)
return err;
ctx->table->use--;
- list_del_rcu(&ctx->chain->list);
+ nft_deactivate_next(ctx->net, ctx->chain);
return err;
}
@@ -559,13 +559,16 @@ err:
return err;
}
-static int nf_tables_table_enable(const struct nft_af_info *afi,
+static int nf_tables_table_enable(struct net *net,
+ const struct nft_af_info *afi,
struct nft_table *table)
{
struct nft_chain *chain;
int err, i = 0;
list_for_each_entry(chain, &table->chains, list) {
+ if (!nft_is_active_next(net, chain))
+ continue;
if (!(chain->flags & NFT_BASE_CHAIN))
continue;
@@ -578,6 +581,8 @@ static int nf_tables_table_enable(const struct nft_af_info *afi,
return 0;
err:
list_for_each_entry(chain, &table->chains, list) {
+ if (!nft_is_active_next(net, chain))
+ continue;
if (!(chain->flags & NFT_BASE_CHAIN))
continue;
@@ -589,12 +594,15 @@ err:
return err;
}
-static void nf_tables_table_disable(const struct nft_af_info *afi,
+static void nf_tables_table_disable(struct net *net,
+ const struct nft_af_info *afi,
struct nft_table *table)
{
struct nft_chain *chain;
list_for_each_entry(chain, &table->chains, list) {
+ if (!nft_is_active_next(net, chain))
+ continue;
if (chain->flags & NFT_BASE_CHAIN)
nft_unregister_basechain(nft_base_chain(chain),
afi->nops);
@@ -627,7 +635,7 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
nft_trans_table_enable(trans) = false;
} else if (!(flags & NFT_TABLE_F_DORMANT) &&
ctx->table->flags & NFT_TABLE_F_DORMANT) {
- ret = nf_tables_table_enable(ctx->afi, ctx->table);
+ ret = nf_tables_table_enable(ctx->net, ctx->afi, ctx->table);
if (ret >= 0) {
ctx->table->flags &= ~NFT_TABLE_F_DORMANT;
nft_trans_table_enable(trans) = true;
@@ -722,6 +730,9 @@ static int nft_flush_table(struct nft_ctx *ctx)
struct nft_set *set, *ns;
list_for_each_entry(chain, &ctx->table->chains, list) {
+ if (!nft_is_active_next(ctx->net, chain))
+ continue;
+
ctx->chain = chain;
err = nft_delrule_by_chain(ctx);
@@ -740,6 +751,9 @@ static int nft_flush_table(struct nft_ctx *ctx)
}
list_for_each_entry_safe(chain, nc, &ctx->table->chains, list) {
+ if (!nft_is_active_next(ctx->net, chain))
+ continue;
+
ctx->chain = chain;
err = nft_delchain(ctx);
@@ -849,12 +863,14 @@ EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
*/
static struct nft_chain *
-nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
+nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle,
+ u8 genmask)
{
struct nft_chain *chain;
list_for_each_entry(chain, &table->chains, list) {
- if (chain->handle == handle)
+ if (chain->handle == handle &&
+ nft_active_genmask(chain, genmask))
return chain;
}
@@ -862,7 +878,8 @@ nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
}
static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
- const struct nlattr *nla)
+ const struct nlattr *nla,
+ u8 genmask)
{
struct nft_chain *chain;
@@ -870,7 +887,8 @@ static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
return ERR_PTR(-EINVAL);
list_for_each_entry(chain, &table->chains, list) {
- if (!nla_strcmp(nla, chain->name))
+ if (!nla_strcmp(nla, chain->name) &&
+ nft_active_genmask(chain, genmask))
return chain;
}
@@ -1053,6 +1071,8 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
if (idx > s_idx)
memset(&cb->args[1], 0,
sizeof(cb->args) - sizeof(cb->args[0]));
+ if (!nft_is_active(net, chain))
+ continue;
if (nf_tables_fill_chain_info(skb, net,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
@@ -1101,11 +1121,9 @@ static int nf_tables_getchain(struct net *net, struct sock *nlsk,
if (IS_ERR(table))
return PTR_ERR(table);
- chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
+ chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
if (IS_ERR(chain))
return PTR_ERR(chain);
- if (chain->flags & NFT_CHAIN_INACTIVE)
- return -ENOENT;
skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb2)
@@ -1230,11 +1248,11 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
if (nla[NFTA_CHAIN_HANDLE]) {
handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
- chain = nf_tables_chain_lookup_byhandle(table, handle);
+ chain = nf_tables_chain_lookup_byhandle(table, handle, genmask);
if (IS_ERR(chain))
return PTR_ERR(chain);
} else {
- chain = nf_tables_chain_lookup(table, name);
+ chain = nf_tables_chain_lookup(table, name, genmask);
if (IS_ERR(chain)) {
if (PTR_ERR(chain) != -ENOENT)
return PTR_ERR(chain);
@@ -1265,16 +1283,20 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
struct nft_stats *stats = NULL;
struct nft_trans *trans;
- if (chain->flags & NFT_CHAIN_INACTIVE)
- return -ENOENT;
if (nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST;
if (nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP;
- if (nla[NFTA_CHAIN_HANDLE] && name &&
- !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
- return -EEXIST;
+ if (nla[NFTA_CHAIN_HANDLE] && name) {
+ struct nft_chain *chain2;
+
+ chain2 = nf_tables_chain_lookup(table,
+ nla[NFTA_CHAIN_NAME],
+ genmask);
+ if (IS_ERR(chain2))
+ return PTR_ERR(chain2);
+ }
if (nla[NFTA_CHAIN_COUNTERS]) {
if (!(chain->flags & NFT_BASE_CHAIN))
@@ -1468,7 +1490,7 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk,
if (IS_ERR(table))
return PTR_ERR(table);
- chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
+ chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
if (IS_ERR(chain))
return PTR_ERR(chain);
if (chain->use > 0)
@@ -1930,11 +1952,9 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
if (IS_ERR(table))
return PTR_ERR(table);
- chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
+ chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN], genmask);
if (IS_ERR(chain))
return PTR_ERR(chain);
- if (chain->flags & NFT_CHAIN_INACTIVE)
- return -ENOENT;
rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
if (IS_ERR(rule))
@@ -2008,7 +2028,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
if (IS_ERR(table))
return PTR_ERR(table);
- chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
+ chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN], genmask);
if (IS_ERR(chain))
return PTR_ERR(chain);
@@ -2166,7 +2186,8 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
return PTR_ERR(table);
if (nla[NFTA_RULE_CHAIN]) {
- chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
+ chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN],
+ genmask);
if (IS_ERR(chain))
return PTR_ERR(chain);
}
@@ -2186,6 +2207,9 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
}
} else {
list_for_each_entry(chain, &table->chains, list) {
+ if (!nft_is_active_next(net, chain))
+ continue;
+
ctx.chain = chain;
err = nft_delrule_by_chain(&ctx);
if (err < 0)
@@ -3933,7 +3957,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
case NFT_MSG_NEWTABLE:
if (nft_trans_table_update(trans)) {
if (!nft_trans_table_enable(trans)) {
- nf_tables_table_disable(trans->ctx.afi,
+ nf_tables_table_disable(net,
+ trans->ctx.afi,
trans->ctx.table);
trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
}
@@ -3951,12 +3976,13 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
if (nft_trans_chain_update(trans))
nft_chain_commit_update(trans);
else
- trans->ctx.chain->flags &= ~NFT_CHAIN_INACTIVE;
+ nft_clear(net, trans->ctx.chain);
nf_tables_chain_notify(&trans->ctx, NFT_MSG_NEWCHAIN);
nft_trans_destroy(trans);
break;
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.table,
trans->ctx.chain,
@@ -4060,7 +4086,8 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
case NFT_MSG_NEWTABLE:
if (nft_trans_table_update(trans)) {
if (nft_trans_table_enable(trans)) {
- nf_tables_table_disable(trans->ctx.afi,
+ nf_tables_table_disable(net,
+ trans->ctx.afi,
trans->ctx.table);
trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
}
@@ -4088,8 +4115,7 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
break;
case NFT_MSG_DELCHAIN:
trans->ctx.table->use++;
- list_add_tail_rcu(&trans->ctx.chain->list,
- &trans->ctx.table->chains);
+ nft_clear(trans->ctx.net, trans->ctx.chain);
nft_trans_destroy(trans);
break;
case NFT_MSG_NEWRULE:
@@ -4413,6 +4439,7 @@ static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
struct nft_data_desc *desc, const struct nlattr *nla)
{
+ u8 genmask = nft_genmask_next(ctx->net);
struct nlattr *tb[NFTA_VERDICT_MAX + 1];
struct nft_chain *chain;
int err;
@@ -4445,7 +4472,7 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
if (!tb[NFTA_VERDICT_CHAIN])
return -EINVAL;
chain = nf_tables_chain_lookup(ctx->table,
- tb[NFTA_VERDICT_CHAIN]);
+ tb[NFTA_VERDICT_CHAIN], genmask);
if (IS_ERR(chain))
return PTR_ERR(chain);
if (chain->flags & NFT_BASE_CHAIN)
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH nf-next 4/6] netfilter: nf_tables: add generation mask to sets
2016-06-22 11:14 [PATCH nf-next 1/6] netfilter: nf_tables: add generic macros to check for generation mask Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 2/6] netfilter: nf_tables: add generation mask to tables Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 3/6] netfilter: nf_tables: add generation mask to chains Pablo Neira Ayuso
@ 2016-06-22 11:14 ` Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 5/6] netfilter: nft_rbtree: check for next generation when deactivating elements Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 6/6] netfilter: nft_hash: support deletion of inactive elements Pablo Neira Ayuso
4 siblings, 0 replies; 7+ messages in thread
From: Pablo Neira Ayuso @ 2016-06-22 11:14 UTC (permalink / raw)
To: netfilter-devel
Similar to ("netfilter: nf_tables: add generation mask to tables").
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_tables.h | 8 +++--
net/netfilter/nf_tables_api.c | 68 +++++++++++++++++++++++----------------
net/netfilter/nft_dynset.c | 7 ++--
net/netfilter/nft_lookup.c | 6 ++--
4 files changed, 54 insertions(+), 35 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 2e97a24..507b0f9 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -297,6 +297,7 @@ void nft_unregister_set(struct nft_set_ops *ops);
* @ops: set ops
* @pnet: network namespace
* @flags: set flags
+ * @genmask: generation mask
* @klen: key length
* @dlen: data length
* @data: private set data
@@ -318,7 +319,8 @@ struct nft_set {
/* runtime data below here */
const struct nft_set_ops *ops ____cacheline_aligned;
possible_net_t pnet;
- u16 flags;
+ u16 flags:14,
+ genmask:2;
u8 klen;
u8 dlen;
unsigned char data[]
@@ -336,9 +338,9 @@ static inline struct nft_set *nft_set_container_of(const void *priv)
}
struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
- const struct nlattr *nla);
+ const struct nlattr *nla, u8 genmask);
struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
- const struct nlattr *nla);
+ const struct nlattr *nla, u8 genmask);
static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
{
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 0581978..3fe2182 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -289,9 +289,6 @@ static int nft_delrule_by_chain(struct nft_ctx *ctx)
return 0;
}
-/* Internal set flag */
-#define NFT_SET_INACTIVE (1 << 15)
-
static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type,
struct nft_set *set)
{
@@ -304,7 +301,7 @@ static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type,
if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] != NULL) {
nft_trans_set_id(trans) =
ntohl(nla_get_be32(ctx->nla[NFTA_SET_ID]));
- set->flags |= NFT_SET_INACTIVE;
+ nft_activate_next(ctx->net, set);
}
nft_trans_set(trans) = set;
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
@@ -320,7 +317,7 @@ static int nft_delset(struct nft_ctx *ctx, struct nft_set *set)
if (err < 0)
return err;
- list_del_rcu(&set->list);
+ nft_deactivate_next(ctx->net, set);
ctx->table->use--;
return err;
@@ -741,6 +738,9 @@ static int nft_flush_table(struct nft_ctx *ctx)
}
list_for_each_entry_safe(set, ns, &ctx->table->sets, list) {
+ if (!nft_is_active_next(ctx->net, set))
+ continue;
+
if (set->flags & NFT_SET_ANONYMOUS &&
!list_empty(&set->bindings))
continue;
@@ -2367,7 +2367,7 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
}
struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
- const struct nlattr *nla)
+ const struct nlattr *nla, u8 genmask)
{
struct nft_set *set;
@@ -2375,22 +2375,27 @@ struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
return ERR_PTR(-EINVAL);
list_for_each_entry(set, &table->sets, list) {
- if (!nla_strcmp(nla, set->name))
+ if (!nla_strcmp(nla, set->name) &&
+ nft_active_genmask(set, genmask))
return set;
}
return ERR_PTR(-ENOENT);
}
struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
- const struct nlattr *nla)
+ const struct nlattr *nla,
+ u8 genmask)
{
struct nft_trans *trans;
u32 id = ntohl(nla_get_be32(nla));
list_for_each_entry(trans, &net->nft.commit_list, list) {
+ struct nft_set *set = nft_trans_set(trans);
+
if (trans->msg_type == NFT_MSG_NEWSET &&
- id == nft_trans_set_id(trans))
- return nft_trans_set(trans);
+ id == nft_trans_set_id(trans) &&
+ nft_active_genmask(set, genmask))
+ return set;
}
return ERR_PTR(-ENOENT);
}
@@ -2415,6 +2420,8 @@ cont:
list_for_each_entry(i, &ctx->table->sets, list) {
int tmp;
+ if (!nft_is_active_next(ctx->net, set))
+ continue;
if (!sscanf(i->name, name, &tmp))
continue;
if (tmp < min || tmp >= min + BITS_PER_BYTE * PAGE_SIZE)
@@ -2434,6 +2441,8 @@ cont:
snprintf(set->name, sizeof(set->name), name, min + n);
list_for_each_entry(i, &ctx->table->sets, list) {
+ if (!nft_is_active_next(ctx->net, i))
+ continue;
if (!strcmp(set->name, i->name))
return -ENFILE;
}
@@ -2582,6 +2591,8 @@ static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
list_for_each_entry_rcu(set, &table->sets, list) {
if (idx < s_idx)
goto cont;
+ if (!nft_is_active(net, set))
+ goto cont;
ctx_set = *ctx;
ctx_set.table = table;
@@ -2653,11 +2664,9 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
if (!nla[NFTA_SET_TABLE])
return -EINVAL;
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
+ set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
if (IS_ERR(set))
return PTR_ERR(set);
- if (set->flags & NFT_SET_INACTIVE)
- return -ENOENT;
skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (skb2 == NULL)
@@ -2800,7 +2809,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
- set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
+ set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME], genmask);
if (IS_ERR(set)) {
if (PTR_ERR(set) != -ENOENT)
return PTR_ERR(set);
@@ -2913,7 +2922,7 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
if (err < 0)
return err;
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
+ set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
if (IS_ERR(set))
return PTR_ERR(set);
if (!list_empty(&set->bindings))
@@ -2978,7 +2987,7 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
list_del_rcu(&binding->list);
if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS &&
- !(set->flags & NFT_SET_INACTIVE))
+ nft_is_active(ctx->net, set))
nf_tables_set_destroy(ctx, set);
}
@@ -3164,11 +3173,10 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
if (err < 0)
return err;
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
+ set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET],
+ genmask);
if (IS_ERR(set))
return PTR_ERR(set);
- if (set->flags & NFT_SET_INACTIVE)
- return -ENOENT;
event = NFT_MSG_NEWSETELEM;
event |= NFNL_SUBSYS_NFTABLES << 8;
@@ -3231,11 +3239,10 @@ static int nf_tables_getsetelem(struct net *net, struct sock *nlsk,
if (err < 0)
return err;
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
+ set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET],
+ genmask);
if (IS_ERR(set))
return PTR_ERR(set);
- if (set->flags & NFT_SET_INACTIVE)
- return -ENOENT;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
@@ -3566,11 +3573,13 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
if (err < 0)
return err;
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
+ set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET],
+ genmask);
if (IS_ERR(set)) {
if (nla[NFTA_SET_ELEM_LIST_SET_ID]) {
set = nf_tables_set_lookup_byid(net,
- nla[NFTA_SET_ELEM_LIST_SET_ID]);
+ nla[NFTA_SET_ELEM_LIST_SET_ID],
+ genmask);
}
if (IS_ERR(set))
return PTR_ERR(set);
@@ -3689,7 +3698,8 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
if (err < 0)
return err;
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
+ set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET],
+ genmask);
if (IS_ERR(set))
return PTR_ERR(set);
if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
@@ -4002,7 +4012,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
NFT_MSG_DELRULE);
break;
case NFT_MSG_NEWSET:
- nft_trans_set(trans)->flags &= ~NFT_SET_INACTIVE;
+ nft_clear(net, nft_trans_set(trans));
/* This avoids hitting -EBUSY when deleting the table
* from the transaction.
*/
@@ -4015,6 +4025,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nft_trans_destroy(trans);
break;
case NFT_MSG_DELSET:
+ list_del_rcu(&nft_trans_set(trans)->list);
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
NFT_MSG_DELSET, GFP_KERNEL);
break;
@@ -4133,8 +4144,7 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
break;
case NFT_MSG_DELSET:
trans->ctx.table->use++;
- list_add_tail_rcu(&nft_trans_set(trans)->list,
- &trans->ctx.table->sets);
+ nft_clear(trans->ctx.net, nft_trans_set(trans));
nft_trans_destroy(trans);
break;
case NFT_MSG_NEWSETELEM:
@@ -4281,6 +4291,8 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
}
list_for_each_entry(set, &ctx->table->sets, list) {
+ if (!nft_is_active_next(ctx->net, set))
+ continue;
if (!(set->flags & NFT_SET_MAP) ||
set->dtype != NFT_DATA_VERDICT)
continue;
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index 78d4914..0af2669 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -103,6 +103,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[])
{
struct nft_dynset *priv = nft_expr_priv(expr);
+ u8 genmask = nft_genmask_next(ctx->net);
struct nft_set *set;
u64 timeout;
int err;
@@ -112,11 +113,13 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
tb[NFTA_DYNSET_SREG_KEY] == NULL)
return -EINVAL;
- set = nf_tables_set_lookup(ctx->table, tb[NFTA_DYNSET_SET_NAME]);
+ set = nf_tables_set_lookup(ctx->table, tb[NFTA_DYNSET_SET_NAME],
+ genmask);
if (IS_ERR(set)) {
if (tb[NFTA_DYNSET_SET_ID])
set = nf_tables_set_lookup_byid(ctx->net,
- tb[NFTA_DYNSET_SET_ID]);
+ tb[NFTA_DYNSET_SET_ID],
+ genmask);
if (IS_ERR(set))
return PTR_ERR(set);
}
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
index b3c31ef..8a102cf 100644
--- a/net/netfilter/nft_lookup.c
+++ b/net/netfilter/nft_lookup.c
@@ -54,6 +54,7 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[])
{
struct nft_lookup *priv = nft_expr_priv(expr);
+ u8 genmask = nft_genmask_next(ctx->net);
struct nft_set *set;
int err;
@@ -61,11 +62,12 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
tb[NFTA_LOOKUP_SREG] == NULL)
return -EINVAL;
- set = nf_tables_set_lookup(ctx->table, tb[NFTA_LOOKUP_SET]);
+ set = nf_tables_set_lookup(ctx->table, tb[NFTA_LOOKUP_SET], genmask);
if (IS_ERR(set)) {
if (tb[NFTA_LOOKUP_SET_ID]) {
set = nf_tables_set_lookup_byid(ctx->net,
- tb[NFTA_LOOKUP_SET_ID]);
+ tb[NFTA_LOOKUP_SET_ID],
+ genmask);
}
if (IS_ERR(set))
return PTR_ERR(set);
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH nf-next 5/6] netfilter: nft_rbtree: check for next generation when deactivating elements
2016-06-22 11:14 [PATCH nf-next 1/6] netfilter: nf_tables: add generic macros to check for generation mask Pablo Neira Ayuso
` (2 preceding siblings ...)
2016-06-22 11:14 ` [PATCH nf-next 4/6] netfilter: nf_tables: add generation mask to sets Pablo Neira Ayuso
@ 2016-06-22 11:14 ` Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 6/6] netfilter: nft_hash: support deletion of inactive elements Pablo Neira Ayuso
4 siblings, 0 replies; 7+ messages in thread
From: Pablo Neira Ayuso @ 2016-06-22 11:14 UTC (permalink / raw)
To: netfilter-devel
set->ops->deactivate() is invoked from nft_del_setelem() that happens
from the transaction path, so we have to check if the object is active
in the next generation, not the current.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nft_rbtree.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/nft_rbtree.c b/net/netfilter/nft_rbtree.c
index 7201d57..c0f6387 100644
--- a/net/netfilter/nft_rbtree.c
+++ b/net/netfilter/nft_rbtree.c
@@ -170,7 +170,7 @@ static void *nft_rbtree_deactivate(const struct nft_set *set,
const struct nft_rbtree *priv = nft_set_priv(set);
const struct rb_node *parent = priv->root.rb_node;
struct nft_rbtree_elem *rbe, *this = elem->priv;
- u8 genmask = nft_genmask_cur(read_pnet(&set->pnet));
+ u8 genmask = nft_genmask_next(read_pnet(&set->pnet));
int d;
while (parent != NULL) {
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH nf-next 6/6] netfilter: nft_hash: support deletion of inactive elements
2016-06-22 11:14 [PATCH nf-next 1/6] netfilter: nf_tables: add generic macros to check for generation mask Pablo Neira Ayuso
` (3 preceding siblings ...)
2016-06-22 11:14 ` [PATCH nf-next 5/6] netfilter: nft_rbtree: check for next generation when deactivating elements Pablo Neira Ayuso
@ 2016-06-22 11:14 ` Pablo Neira Ayuso
4 siblings, 0 replies; 7+ messages in thread
From: Pablo Neira Ayuso @ 2016-06-22 11:14 UTC (permalink / raw)
To: netfilter-devel
New elements are inactive in the preparation phase, and its
NFT_SET_ELEM_BUSY_MASK flag is set on.
This busy flag doesn't allow us to delete it from the same transaction,
following a sequence like:
begin transaction
add element X
delete element X
end transaction
This sequence is valid and may be triggered by robots. To resolve this
problem, allow deactivating elements that are active in the current
generation (ie. those that has been just added in this batch).
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nft_hash.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c
index f39c53a..ea92481 100644
--- a/net/netfilter/nft_hash.c
+++ b/net/netfilter/nft_hash.c
@@ -153,9 +153,10 @@ static void *nft_hash_deactivate(const struct nft_set *set,
const struct nft_set_elem *elem)
{
struct nft_hash *priv = nft_set_priv(set);
+ struct net *net = read_pnet(&set->pnet);
struct nft_hash_elem *he;
struct nft_hash_cmp_arg arg = {
- .genmask = nft_genmask_next(read_pnet(&set->pnet)),
+ .genmask = nft_genmask_next(net),
.set = set,
.key = elem->key.val.data,
};
@@ -163,7 +164,8 @@ static void *nft_hash_deactivate(const struct nft_set *set,
rcu_read_lock();
he = rhashtable_lookup_fast(&priv->ht, &arg, nft_hash_params);
if (he != NULL) {
- if (!nft_set_elem_mark_busy(&he->ext))
+ if (!nft_set_elem_mark_busy(&he->ext) ||
+ !nft_is_active(net, &he->ext))
nft_set_elem_change_active(set, &he->ext);
else
he = NULL;
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH nf-next 2/6] netfilter: nf_tables: add generation mask to tables
2016-06-22 11:14 ` [PATCH nf-next 2/6] netfilter: nf_tables: add generation mask to tables Pablo Neira Ayuso
@ 2016-06-22 11:50 ` Pablo Neira Ayuso
0 siblings, 0 replies; 7+ messages in thread
From: Pablo Neira Ayuso @ 2016-06-22 11:50 UTC (permalink / raw)
To: netfilter-devel
On Wed, Jun 22, 2016 at 01:14:28PM +0200, Pablo Neira Ayuso wrote:
> 2) We don't allow adding and deleting object a given object X in the
> same batch.
I'm revisiting this statement, which is actually not true. This is
indeed working, what is currently broken (and this patch fixes) is:
add table x
add table x { flags dormant\; }
ie. add and update in the same transaction via nft -f.
Same thing with the follow up patch for chains, eg.
add chain x y { type filter hook input priority 0\; }
add chain x y { policy drop\; }
which is a valid sequence that currently doesn't work.
So I'm rewriting this patch description to the following below.
-o-
netfilter: nf_tables: add generation mask to tables
This patch addresses two problems:
1) The netlink dump is inconsistent when interfering with an ongoing
transaction update for several reasons:
1.a) We don't honor the internal NFT_TABLE_INACTIVE flag, and we should
be skipping these inactive objects in the dump.
1.b) We perform speculative deletion during the preparation phase, that
may result in skipping active objects.
1.c) The listing order changes, which generates noise when tracking
incremental ruleset update via tools like git or our own
testsuite.
2) We don't allow to add and to update the object in the same batch,
eg. add table x; add table x { flags dormant\; }.
In order to resolve these problems:
1) If the user requests a deletion, the object becomes inactive in the
next generation. Then, ignore objects that scheduled to be deleted
from the lookup path, as they will be effectively removed in the
next generation.
2) From the get/dump path, if the object is not currently active, we
skip it.
3) Support 'add X -> update X' sequence from a transaction.
After this update, we obtain a consistent list as long as we stay
in the same generation. The userspace side can detect interferences
through the generation counter so it can restart the dumping.
>
> In order to resolve these problems:
>
> 1) If the user requests a deletion, the object becomes inactive in the
> next generation. Then, ignore objects that scheduled to be deleted
> from the lookup path, as they will be effectively removed in the
> next generation.
>
> 2) From the get/dump path, if the object is not currently active, we
> skip it.
>
> 3) Support 'add X -> delete X -> add X' sequences from a transaction,
> they are valid since robot may trigger these kind of incremental
> updates.
>
> After this update, we obtain a consistent list as long as we stay
> in the same generation. The userspace side can detect interferences
> through the generation counter so it can restart the dumping.
>
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
> ---
> include/net/netfilter/nf_tables.h | 6 ++-
> net/netfilter/nf_tables_api.c | 101 +++++++++++++++++++++-----------------
> 2 files changed, 62 insertions(+), 45 deletions(-)
>
> diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
> index 6b7ce3a..5b802f8 100644
> --- a/include/net/netfilter/nf_tables.h
> +++ b/include/net/netfilter/nf_tables.h
> @@ -839,6 +839,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);
> * @hgenerator: handle generator state
> * @use: number of chain references to this table
> * @flags: table flag (see enum nft_table_flags)
> + * @genmask: generation mask
> * @name: name of the table
> */
> struct nft_table {
> @@ -847,7 +848,8 @@ struct nft_table {
> struct list_head sets;
> u64 hgenerator;
> u32 use;
> - u16 flags;
> + u16 flags:14,
> + genmask:2;
> char name[NFT_TABLE_MAXNAMELEN];
> };
>
> @@ -993,6 +995,8 @@ static inline u8 nft_genmask_cur(const struct net *net)
> /* After committing the ruleset, clear the stale generation bit. */
> #define nft_clear(__net, __obj) \
> (__obj)->genmask &= ~nft_genmask_next(__net)
> +#define nft_active_genmask(__obj, __genmask) \
> + !((__obj)->genmask & __genmask)
>
> /*
> * Set element transaction helpers
> diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
> index bae7d67..4cdc591 100644
> --- a/net/netfilter/nf_tables_api.c
> +++ b/net/netfilter/nf_tables_api.c
> @@ -175,9 +175,6 @@ static void nf_tables_unregister_hooks(const struct nft_table *table,
> nft_unregister_basechain(nft_base_chain(chain), hook_nops);
> }
>
> -/* Internal table flags */
> -#define NFT_TABLE_INACTIVE (1 << 15)
> -
> static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
> {
> struct nft_trans *trans;
> @@ -187,7 +184,7 @@ static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
> return -ENOMEM;
>
> if (msg_type == NFT_MSG_NEWTABLE)
> - ctx->table->flags |= NFT_TABLE_INACTIVE;
> + nft_activate_next(ctx->net, ctx->table);
>
> list_add_tail(&trans->list, &ctx->net->nft.commit_list);
> return 0;
> @@ -201,7 +198,7 @@ static int nft_deltable(struct nft_ctx *ctx)
> if (err < 0)
> return err;
>
> - list_del_rcu(&ctx->table->list);
> + nft_deactivate_next(ctx->net, ctx->table);
> return err;
> }
>
> @@ -334,26 +331,29 @@ static int nft_delset(struct nft_ctx *ctx, struct nft_set *set)
> */
>
> static struct nft_table *nft_table_lookup(const struct nft_af_info *afi,
> - const struct nlattr *nla)
> + const struct nlattr *nla,
> + u8 genmask)
> {
> struct nft_table *table;
>
> list_for_each_entry(table, &afi->tables, list) {
> - if (!nla_strcmp(nla, table->name))
> + if (!nla_strcmp(nla, table->name) &&
> + nft_active_genmask(table, genmask))
> return table;
> }
> return NULL;
> }
>
> static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi,
> - const struct nlattr *nla)
> + const struct nlattr *nla,
> + u8 genmask)
> {
> struct nft_table *table;
>
> if (nla == NULL)
> return ERR_PTR(-EINVAL);
>
> - table = nft_table_lookup(afi, nla);
> + table = nft_table_lookup(afi, nla, genmask);
> if (table != NULL)
> return table;
>
> @@ -494,6 +494,8 @@ static int nf_tables_dump_tables(struct sk_buff *skb,
> if (idx > s_idx)
> memset(&cb->args[1], 0,
> sizeof(cb->args) - sizeof(cb->args[0]));
> + if (!nft_is_active(net, table))
> + continue;
> if (nf_tables_fill_table_info(skb, net,
> NETLINK_CB(cb->skb).portid,
> cb->nlh->nlmsg_seq,
> @@ -518,6 +520,7 @@ static int nf_tables_gettable(struct net *net, struct sock *nlsk,
> const struct nlattr * const nla[])
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> + u8 genmask = nft_genmask_cur(net);
> const struct nft_af_info *afi;
> const struct nft_table *table;
> struct sk_buff *skb2;
> @@ -535,11 +538,9 @@ static int nf_tables_gettable(struct net *net, struct sock *nlsk,
> if (IS_ERR(afi))
> return PTR_ERR(afi);
>
> - table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
> + table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME], genmask);
> if (IS_ERR(table))
> return PTR_ERR(table);
> - if (table->flags & NFT_TABLE_INACTIVE)
> - return -ENOENT;
>
> skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
> if (!skb2)
> @@ -648,6 +649,7 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
> const struct nlattr * const nla[])
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> + u8 genmask = nft_genmask_next(net);
> const struct nlattr *name;
> struct nft_af_info *afi;
> struct nft_table *table;
> @@ -661,7 +663,7 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
> return PTR_ERR(afi);
>
> name = nla[NFTA_TABLE_NAME];
> - table = nf_tables_table_lookup(afi, name);
> + table = nf_tables_table_lookup(afi, name, genmask);
> if (IS_ERR(table)) {
> if (PTR_ERR(table) != -ENOENT)
> return PTR_ERR(table);
> @@ -669,8 +671,6 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
> }
>
> if (table != NULL) {
> - if (table->flags & NFT_TABLE_INACTIVE)
> - return -ENOENT;
> if (nlh->nlmsg_flags & NLM_F_EXCL)
> return -EEXIST;
> if (nlh->nlmsg_flags & NLM_F_REPLACE)
> @@ -765,6 +765,9 @@ static int nft_flush(struct nft_ctx *ctx, int family)
>
> ctx->afi = afi;
> list_for_each_entry_safe(table, nt, &afi->tables, list) {
> + if (!nft_is_active_next(ctx->net, table))
> + continue;
> +
> if (nla[NFTA_TABLE_NAME] &&
> nla_strcmp(nla[NFTA_TABLE_NAME], table->name) != 0)
> continue;
> @@ -785,6 +788,7 @@ static int nf_tables_deltable(struct net *net, struct sock *nlsk,
> const struct nlattr * const nla[])
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> + u8 genmask = nft_genmask_next(net);
> struct nft_af_info *afi;
> struct nft_table *table;
> int family = nfmsg->nfgen_family;
> @@ -798,7 +802,7 @@ static int nf_tables_deltable(struct net *net, struct sock *nlsk,
> if (IS_ERR(afi))
> return PTR_ERR(afi);
>
> - table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
> + table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME], genmask);
> if (IS_ERR(table))
> return PTR_ERR(table);
>
> @@ -1074,6 +1078,7 @@ static int nf_tables_getchain(struct net *net, struct sock *nlsk,
> const struct nlattr * const nla[])
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> + u8 genmask = nft_genmask_cur(net);
> const struct nft_af_info *afi;
> const struct nft_table *table;
> const struct nft_chain *chain;
> @@ -1092,11 +1097,9 @@ static int nf_tables_getchain(struct net *net, struct sock *nlsk,
> if (IS_ERR(afi))
> return PTR_ERR(afi);
>
> - table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
> + table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE], genmask);
> if (IS_ERR(table))
> return PTR_ERR(table);
> - if (table->flags & NFT_TABLE_INACTIVE)
> - return -ENOENT;
>
> chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
> if (IS_ERR(chain))
> @@ -1201,6 +1204,7 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
> struct nft_chain *chain;
> struct nft_base_chain *basechain = NULL;
> struct nlattr *ha[NFTA_HOOK_MAX + 1];
> + u8 genmask = nft_genmask_next(net);
> int family = nfmsg->nfgen_family;
> struct net_device *dev = NULL;
> u8 policy = NF_ACCEPT;
> @@ -1217,7 +1221,7 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
> if (IS_ERR(afi))
> return PTR_ERR(afi);
>
> - table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
> + table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE], genmask);
> if (IS_ERR(table))
> return PTR_ERR(table);
>
> @@ -1449,6 +1453,7 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk,
> const struct nlattr * const nla[])
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> + u8 genmask = nft_genmask_next(net);
> struct nft_af_info *afi;
> struct nft_table *table;
> struct nft_chain *chain;
> @@ -1459,7 +1464,7 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk,
> if (IS_ERR(afi))
> return PTR_ERR(afi);
>
> - table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
> + table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE], genmask);
> if (IS_ERR(table))
> return PTR_ERR(table);
>
> @@ -1901,6 +1906,7 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
> const struct nlattr * const nla[])
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> + u8 genmask = nft_genmask_cur(net);
> const struct nft_af_info *afi;
> const struct nft_table *table;
> const struct nft_chain *chain;
> @@ -1920,11 +1926,9 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
> if (IS_ERR(afi))
> return PTR_ERR(afi);
>
> - table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
> + table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE], genmask);
> if (IS_ERR(table))
> return PTR_ERR(table);
> - if (table->flags & NFT_TABLE_INACTIVE)
> - return -ENOENT;
>
> chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
> if (IS_ERR(chain))
> @@ -1979,6 +1983,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
> const struct nlattr * const nla[])
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> + u8 genmask = nft_genmask_next(net);
> struct nft_af_info *afi;
> struct nft_table *table;
> struct nft_chain *chain;
> @@ -1999,7 +2004,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
> if (IS_ERR(afi))
> return PTR_ERR(afi);
>
> - table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
> + table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE], genmask);
> if (IS_ERR(table))
> return PTR_ERR(table);
>
> @@ -2144,6 +2149,7 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
> const struct nlattr * const nla[])
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> + u8 genmask = nft_genmask_next(net);
> struct nft_af_info *afi;
> struct nft_table *table;
> struct nft_chain *chain = NULL;
> @@ -2155,7 +2161,7 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
> if (IS_ERR(afi))
> return PTR_ERR(afi);
>
> - table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
> + table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE], genmask);
> if (IS_ERR(table))
> return PTR_ERR(table);
>
> @@ -2309,7 +2315,8 @@ static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
> static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
> const struct sk_buff *skb,
> const struct nlmsghdr *nlh,
> - const struct nlattr * const nla[])
> + const struct nlattr * const nla[],
> + u8 genmask)
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> struct nft_af_info *afi = NULL;
> @@ -2325,7 +2332,8 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
> if (afi == NULL)
> return -EAFNOSUPPORT;
>
> - table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
> + table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE],
> + genmask);
> if (IS_ERR(table))
> return PTR_ERR(table);
> }
> @@ -2586,6 +2594,7 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
> struct sk_buff *skb, const struct nlmsghdr *nlh,
> const struct nlattr * const nla[])
> {
> + u8 genmask = nft_genmask_cur(net);
> const struct nft_set *set;
> struct nft_ctx ctx;
> struct sk_buff *skb2;
> @@ -2593,7 +2602,7 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
> int err;
>
> /* Verify existence before starting dump */
> - err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla);
> + err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla, genmask);
> if (err < 0)
> return err;
>
> @@ -2663,6 +2672,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
> const struct nlattr * const nla[])
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> + u8 genmask = nft_genmask_next(net);
> const struct nft_set_ops *ops;
> struct nft_af_info *afi;
> struct nft_table *table;
> @@ -2760,7 +2770,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
> if (IS_ERR(afi))
> return PTR_ERR(afi);
>
> - table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
> + table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE], genmask);
> if (IS_ERR(table))
> return PTR_ERR(table);
>
> @@ -2865,6 +2875,7 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
> const struct nlattr * const nla[])
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> + u8 genmask = nft_genmask_next(net);
> struct nft_set *set;
> struct nft_ctx ctx;
> int err;
> @@ -2874,7 +2885,7 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
> if (nla[NFTA_SET_TABLE] == NULL)
> return -EINVAL;
>
> - err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla);
> + err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla, genmask);
> if (err < 0)
> return err;
>
> @@ -2999,7 +3010,8 @@ static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX +
> static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
> const struct sk_buff *skb,
> const struct nlmsghdr *nlh,
> - const struct nlattr * const nla[])
> + const struct nlattr * const nla[],
> + u8 genmask)
> {
> const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
> struct nft_af_info *afi;
> @@ -3009,7 +3021,8 @@ static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
> if (IS_ERR(afi))
> return PTR_ERR(afi);
>
> - table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
> + table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE],
> + genmask);
> if (IS_ERR(table))
> return PTR_ERR(table);
>
> @@ -3106,6 +3119,7 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
> static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
> {
> struct net *net = sock_net(skb->sk);
> + u8 genmask = nft_genmask_cur(net);
> const struct nft_set *set;
> struct nft_set_dump_args args;
> struct nft_ctx ctx;
> @@ -3122,11 +3136,9 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
> return err;
>
> err = nft_ctx_init_from_elemattr(&ctx, net, cb->skb, cb->nlh,
> - (void *)nla);
> + (void *)nla, genmask);
> if (err < 0)
> return err;
> - if (ctx.table->flags & NFT_TABLE_INACTIVE)
> - return -ENOENT;
>
> set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
> if (IS_ERR(set))
> @@ -3186,15 +3198,14 @@ static int nf_tables_getsetelem(struct net *net, struct sock *nlsk,
> struct sk_buff *skb, const struct nlmsghdr *nlh,
> const struct nlattr * const nla[])
> {
> + u8 genmask = nft_genmask_cur(net);
> const struct nft_set *set;
> struct nft_ctx ctx;
> int err;
>
> - err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
> + err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, genmask);
> if (err < 0)
> return err;
> - if (ctx.table->flags & NFT_TABLE_INACTIVE)
> - return -ENOENT;
>
> set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
> if (IS_ERR(set))
> @@ -3518,6 +3529,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
> struct sk_buff *skb, const struct nlmsghdr *nlh,
> const struct nlattr * const nla[])
> {
> + u8 genmask = nft_genmask_next(net);
> const struct nlattr *attr;
> struct nft_set *set;
> struct nft_ctx ctx;
> @@ -3526,7 +3538,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
> if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
> return -EINVAL;
>
> - err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
> + err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, genmask);
> if (err < 0)
> return err;
>
> @@ -3640,6 +3652,7 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
> struct sk_buff *skb, const struct nlmsghdr *nlh,
> const struct nlattr * const nla[])
> {
> + u8 genmask = nft_genmask_next(net);
> const struct nlattr *attr;
> struct nft_set *set;
> struct nft_ctx ctx;
> @@ -3648,7 +3661,7 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
> if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
> return -EINVAL;
>
> - err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
> + err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, genmask);
> if (err < 0)
> return err;
>
> @@ -3925,12 +3938,13 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
> trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
> }
> } else {
> - trans->ctx.table->flags &= ~NFT_TABLE_INACTIVE;
> + nft_clear(net, trans->ctx.table);
> }
> nf_tables_table_notify(&trans->ctx, NFT_MSG_NEWTABLE);
> nft_trans_destroy(trans);
> break;
> case NFT_MSG_DELTABLE:
> + list_del_rcu(&trans->ctx.table->list);
> nf_tables_table_notify(&trans->ctx, NFT_MSG_DELTABLE);
> break;
> case NFT_MSG_NEWCHAIN:
> @@ -4056,8 +4070,7 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
> }
> break;
> case NFT_MSG_DELTABLE:
> - list_add_tail_rcu(&trans->ctx.table->list,
> - &trans->ctx.afi->tables);
> + nft_clear(trans->ctx.net, trans->ctx.table);
> nft_trans_destroy(trans);
> break;
> case NFT_MSG_NEWCHAIN:
> --
> 2.1.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2016-06-22 12:00 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-06-22 11:14 [PATCH nf-next 1/6] netfilter: nf_tables: add generic macros to check for generation mask Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 2/6] netfilter: nf_tables: add generation mask to tables Pablo Neira Ayuso
2016-06-22 11:50 ` Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 3/6] netfilter: nf_tables: add generation mask to chains Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 4/6] netfilter: nf_tables: add generation mask to sets Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 5/6] netfilter: nft_rbtree: check for next generation when deactivating elements Pablo Neira Ayuso
2016-06-22 11:14 ` [PATCH nf-next 6/6] netfilter: nft_hash: support deletion of inactive elements 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).