summaryrefslogtreecommitdiffstats
path: root/net/netfilter/nft_dynset.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2020-12-07 17:37:14 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2020-12-12 19:20:52 +0100
commit48b0ae046ee96eac999839f6d26c624b8c93ed66 (patch)
treeaca93688b8f9d6b909d8b6634f03d2e9b7ccb6e0 /net/netfilter/nft_dynset.c
parent563125a73ac30d7036ae69ca35c40500562c1de4 (diff)
netfilter: nftables: netlink support for several set element expressions
This patch adds three new netlink attributes to encapsulate a list of expressions per set elements: - NFTA_SET_EXPRESSIONS: this attribute provides the set definition in terms of expressions. New set elements get attached the list of expressions that is specified by this new netlink attribute. - NFTA_SET_ELEM_EXPRESSIONS: this attribute allows users to restore (or initialize) the stateful information of set elements when adding an element to the set. - NFTA_DYNSET_EXPRESSIONS: this attribute specifies the list of expressions that the set element gets when it is inserted from the packet path. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter/nft_dynset.c')
-rw-r--r--net/netfilter/nft_dynset.c56
1 files changed, 53 insertions, 3 deletions
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index d9e609b2e5d4..13c426d5dcf9 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -153,6 +153,7 @@ static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = {
[NFTA_DYNSET_TIMEOUT] = { .type = NLA_U64 },
[NFTA_DYNSET_EXPR] = { .type = NLA_NESTED },
[NFTA_DYNSET_FLAGS] = { .type = NLA_U32 },
+ [NFTA_DYNSET_EXPRESSIONS] = { .type = NLA_NESTED },
};
static int nft_dynset_init(const struct nft_ctx *ctx,
@@ -232,12 +233,13 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
} else if (set->flags & NFT_SET_MAP)
return -EINVAL;
+ if ((tb[NFTA_DYNSET_EXPR] || tb[NFTA_DYNSET_EXPRESSIONS]) &&
+ !(set->flags & NFT_SET_EVAL))
+ return -EINVAL;
+
if (tb[NFTA_DYNSET_EXPR]) {
struct nft_expr *dynset_expr;
- if (!(set->flags & NFT_SET_EVAL))
- return -EINVAL;
-
dynset_expr = nft_dynset_expr_alloc(ctx, set,
tb[NFTA_DYNSET_EXPR], 0);
if (IS_ERR(dynset_expr))
@@ -252,6 +254,40 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
err = -EOPNOTSUPP;
goto err_expr_free;
}
+ } else if (tb[NFTA_DYNSET_EXPRESSIONS]) {
+ struct nft_expr *dynset_expr;
+ struct nlattr *tmp;
+ int left;
+
+ i = 0;
+ nla_for_each_nested(tmp, tb[NFTA_DYNSET_EXPRESSIONS], left) {
+ if (i == NFT_SET_EXPR_MAX) {
+ err = -E2BIG;
+ goto err_expr_free;
+ }
+ if (nla_type(tmp) != NFTA_LIST_ELEM) {
+ err = -EINVAL;
+ goto err_expr_free;
+ }
+ dynset_expr = nft_dynset_expr_alloc(ctx, set, tmp, i);
+ if (IS_ERR(dynset_expr)) {
+ err = PTR_ERR(dynset_expr);
+ goto err_expr_free;
+ }
+ priv->expr_array[i] = dynset_expr;
+ priv->num_exprs++;
+
+ if (set->num_exprs &&
+ dynset_expr->ops != set->exprs[i]->ops) {
+ err = -EOPNOTSUPP;
+ goto err_expr_free;
+ }
+ i++;
+ }
+ if (set->num_exprs && set->num_exprs != i) {
+ err = -EOPNOTSUPP;
+ goto err_expr_free;
+ }
}
nft_set_ext_prepare(&priv->tmpl);
@@ -318,6 +354,7 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
{
const struct nft_dynset *priv = nft_expr_priv(expr);
u32 flags = priv->invert ? NFT_DYNSET_F_INV : 0;
+ int i;
if (nft_dump_register(skb, NFTA_DYNSET_SREG_KEY, priv->sreg_key))
goto nla_put_failure;
@@ -335,6 +372,19 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
if (priv->num_exprs == 1) {
if (nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr_array[0]))
goto nla_put_failure;
+ } else if (priv->num_exprs > 1) {
+ struct nlattr *nest;
+
+ nest = nla_nest_start_noflag(skb, NFTA_DYNSET_EXPRESSIONS);
+ if (!nest)
+ goto nla_put_failure;
+
+ for (i = 0; i < priv->num_exprs; i++) {
+ if (nft_expr_dump(skb, NFTA_LIST_ELEM,
+ priv->expr_array[i]))
+ goto nla_put_failure;
+ }
+ nla_nest_end(skb, nest);
}
if (nla_put_be32(skb, NFTA_DYNSET_FLAGS, htonl(flags)))
goto nla_put_failure;