Commit 29b359cf authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: nft_set_pipapo: walk over current view on netlink dump

The generation mask can be updated while netlink dump is in progress.
The pipapo set backend walk iterator cannot rely on it to infer what
view of the datastructure is to be used. Add notation to specify if user
wants to read/update the set.

Based on patch from Florian Westphal.

Fixes: 2b84e215 ("netfilter: nft_set_pipapo: .walk does not deal with generations")
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 751de201
...@@ -307,9 +307,23 @@ static inline void *nft_elem_priv_cast(const struct nft_elem_priv *priv) ...@@ -307,9 +307,23 @@ static inline void *nft_elem_priv_cast(const struct nft_elem_priv *priv)
return (void *)priv; return (void *)priv;
} }
/**
* enum nft_iter_type - nftables set iterator type
*
* @NFT_ITER_READ: read-only iteration over set elements
* @NFT_ITER_UPDATE: iteration under mutex to update set element state
*/
enum nft_iter_type {
NFT_ITER_UNSPEC,
NFT_ITER_READ,
NFT_ITER_UPDATE,
};
struct nft_set; struct nft_set;
struct nft_set_iter { struct nft_set_iter {
u8 genmask; u8 genmask;
enum nft_iter_type type:8;
unsigned int count; unsigned int count;
unsigned int skip; unsigned int skip;
int err; int err;
......
...@@ -626,6 +626,7 @@ static void nft_map_deactivate(const struct nft_ctx *ctx, struct nft_set *set) ...@@ -626,6 +626,7 @@ static void nft_map_deactivate(const struct nft_ctx *ctx, struct nft_set *set)
{ {
struct nft_set_iter iter = { struct nft_set_iter iter = {
.genmask = nft_genmask_next(ctx->net), .genmask = nft_genmask_next(ctx->net),
.type = NFT_ITER_UPDATE,
.fn = nft_mapelem_deactivate, .fn = nft_mapelem_deactivate,
}; };
...@@ -5445,6 +5446,7 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, ...@@ -5445,6 +5446,7 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
} }
iter.genmask = nft_genmask_next(ctx->net); iter.genmask = nft_genmask_next(ctx->net);
iter.type = NFT_ITER_UPDATE;
iter.skip = 0; iter.skip = 0;
iter.count = 0; iter.count = 0;
iter.err = 0; iter.err = 0;
...@@ -5518,6 +5520,7 @@ static void nft_map_activate(const struct nft_ctx *ctx, struct nft_set *set) ...@@ -5518,6 +5520,7 @@ static void nft_map_activate(const struct nft_ctx *ctx, struct nft_set *set)
{ {
struct nft_set_iter iter = { struct nft_set_iter iter = {
.genmask = nft_genmask_next(ctx->net), .genmask = nft_genmask_next(ctx->net),
.type = NFT_ITER_UPDATE,
.fn = nft_mapelem_activate, .fn = nft_mapelem_activate,
}; };
...@@ -5892,6 +5895,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -5892,6 +5895,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
args.skb = skb; args.skb = skb;
args.reset = dump_ctx->reset; args.reset = dump_ctx->reset;
args.iter.genmask = nft_genmask_cur(net); args.iter.genmask = nft_genmask_cur(net);
args.iter.type = NFT_ITER_READ;
args.iter.skip = cb->args[0]; args.iter.skip = cb->args[0];
args.iter.count = 0; args.iter.count = 0;
args.iter.err = 0; args.iter.err = 0;
...@@ -7376,6 +7380,7 @@ static int nft_set_flush(struct nft_ctx *ctx, struct nft_set *set, u8 genmask) ...@@ -7376,6 +7380,7 @@ static int nft_set_flush(struct nft_ctx *ctx, struct nft_set *set, u8 genmask)
{ {
struct nft_set_iter iter = { struct nft_set_iter iter = {
.genmask = genmask, .genmask = genmask,
.type = NFT_ITER_UPDATE,
.fn = nft_setelem_flush, .fn = nft_setelem_flush,
}; };
...@@ -10879,6 +10884,7 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx, ...@@ -10879,6 +10884,7 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
continue; continue;
iter.genmask = nft_genmask_next(ctx->net); iter.genmask = nft_genmask_next(ctx->net);
iter.type = NFT_ITER_UPDATE;
iter.skip = 0; iter.skip = 0;
iter.count = 0; iter.count = 0;
iter.err = 0; iter.err = 0;
......
...@@ -2115,13 +2115,14 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set, ...@@ -2115,13 +2115,14 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_iter *iter) struct nft_set_iter *iter)
{ {
struct nft_pipapo *priv = nft_set_priv(set); struct nft_pipapo *priv = nft_set_priv(set);
struct net *net = read_pnet(&set->net);
const struct nft_pipapo_match *m; const struct nft_pipapo_match *m;
const struct nft_pipapo_field *f; const struct nft_pipapo_field *f;
unsigned int i, r; unsigned int i, r;
WARN_ON_ONCE(iter->type == NFT_ITER_UNSPEC);
rcu_read_lock(); rcu_read_lock();
if (iter->genmask == nft_genmask_cur(net)) if (iter->type == NFT_ITER_READ)
m = rcu_dereference(priv->match); m = rcu_dereference(priv->match);
else else
m = priv->clone; m = priv->clone;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment