Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_tables: support different set binding types

Currently a set binding is assumed to be related to a lookup and, in
case of maps, a data load.

In order to use bindings for set updates, the loop detection checks
must be restricted to map operations only. Add a flags member to the
binding struct to hold the set "action" flags such as NFT_SET_MAP,
and perform loop detection based on these.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Patrick McHardy and committed by
Pablo Neira Ayuso
11113e19 3dd0673a

+12 -3
+2
include/net/netfilter/nf_tables.h
··· 316 316 * 317 317 * @list: set bindings list node 318 318 * @chain: chain containing the rule bound to the set 319 + * @flags: set action flags 319 320 * 320 321 * A set binding contains all information necessary for validation 321 322 * of new elements added to a bound set. ··· 324 323 struct nft_set_binding { 325 324 struct list_head list; 326 325 const struct nft_chain *chain; 326 + u32 flags; 327 327 }; 328 328 329 329 int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
+8 -3
net/netfilter/nf_tables_api.c
··· 2811 2811 if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS) 2812 2812 return -EBUSY; 2813 2813 2814 - if (set->flags & NFT_SET_MAP) { 2814 + if (binding->flags & NFT_SET_MAP) { 2815 2815 /* If the set is already bound to the same chain all 2816 2816 * jumps are already validated for that chain. 2817 2817 */ 2818 2818 list_for_each_entry(i, &set->bindings, list) { 2819 - if (i->chain == binding->chain) 2819 + if (binding->flags & NFT_SET_MAP && 2820 + i->chain == binding->chain) 2820 2821 goto bind; 2821 2822 } 2822 2823 ··· 3312 3311 .table = ctx->table, 3313 3312 .chain = (struct nft_chain *)binding->chain, 3314 3313 }; 3314 + 3315 + if (!(binding->flags & NFT_SET_MAP)) 3316 + continue; 3315 3317 3316 3318 err = nft_validate_data_load(&bind_ctx, dreg, 3317 3319 &data, d2.type); ··· 4067 4063 continue; 4068 4064 4069 4065 list_for_each_entry(binding, &set->bindings, list) { 4070 - if (binding->chain != chain) 4066 + if (!(binding->flags & NFT_SET_MAP) || 4067 + binding->chain != chain) 4071 4068 continue; 4072 4069 4073 4070 iter.skip = 0;
+2
net/netfilter/nft_lookup.c
··· 92 92 } else if (set->flags & NFT_SET_MAP) 93 93 return -EINVAL; 94 94 95 + priv->binding.flags = set->flags & NFT_SET_MAP; 96 + 95 97 err = nf_tables_bind_set(ctx, set, &priv->binding); 96 98 if (err < 0) 97 99 return err;