From: Patrick McHardy Date: Sun, 5 Apr 2015 12:41:07 +0000 (+0200) Subject: netfilter: nf_tables: support different set binding types X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=11113e190bf0ad73086884f87efccc994ff28b3d;p=openwrt%2Fstaging%2Fblogic.git 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 Signed-off-by: Pablo Neira Ayuso --- diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 746423332fcb..e7e6365c248f 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -316,6 +316,7 @@ static inline unsigned long nft_set_gc_interval(const struct nft_set *set) * * @list: set bindings list node * @chain: chain containing the rule bound to the set + * @flags: set action flags * * A set binding contains all information necessary for validation * of new elements added to a bound set. @@ -323,6 +324,7 @@ static inline unsigned long nft_set_gc_interval(const struct nft_set *set) struct nft_set_binding { struct list_head list; const struct nft_chain *chain; + u32 flags; }; int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 27d1bf55a581..90b898491da7 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2811,12 +2811,13 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS) return -EBUSY; - if (set->flags & NFT_SET_MAP) { + if (binding->flags & NFT_SET_MAP) { /* If the set is already bound to the same chain all * jumps are already validated for that chain. */ list_for_each_entry(i, &set->bindings, list) { - if (i->chain == binding->chain) + if (binding->flags & NFT_SET_MAP && + i->chain == binding->chain) goto bind; } @@ -3312,6 +3313,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, .chain = (struct nft_chain *)binding->chain, }; + if (!(binding->flags & NFT_SET_MAP)) + continue; + err = nft_validate_data_load(&bind_ctx, dreg, &data, d2.type); if (err < 0) @@ -4063,7 +4067,8 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx, continue; list_for_each_entry(binding, &set->bindings, list) { - if (binding->chain != chain) + if (!(binding->flags & NFT_SET_MAP) || + binding->chain != chain) continue; iter.skip = 0; diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c index a5f30b8760ea..d8cf86fb30fc 100644 --- a/net/netfilter/nft_lookup.c +++ b/net/netfilter/nft_lookup.c @@ -92,6 +92,8 @@ static int nft_lookup_init(const struct nft_ctx *ctx, } else if (set->flags & NFT_SET_MAP) return -EINVAL; + priv->binding.flags = set->flags & NFT_SET_MAP; + err = nf_tables_bind_set(ctx, set, &priv->binding); if (err < 0) return err;