* [RFC PATCH nft 1/6] set: allow non-constant implicit set declarations
2015-11-06 18:34 [RFC PATCH nft 0/6] flow statement Patrick McHardy
@ 2015-11-06 18:34 ` Patrick McHardy
2015-11-06 18:34 ` [RFC PATCH nft 2/6] set: explicitly supply name to " Patrick McHardy
` (6 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Patrick McHardy @ 2015-11-06 18:34 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Currently all implicitly declared sets are marked as constant. The flow
statement needs to implicitly declare non-constant sets, so instead of
unconditionally marking the set as constant, only do so if the declaring
expression is itself a constant set.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
src/evaluate.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index 7842471..f53ba5e 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -90,7 +90,7 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
struct handle h;
set = set_alloc(&expr->location);
- set->flags = SET_F_CONSTANT | SET_F_ANONYMOUS | expr->set_flags;
+ set->flags = SET_F_ANONYMOUS | expr->set_flags;
set->handle.set = xstrdup(set->flags & SET_F_MAP ? "map%d" : "set%d");
set->keytype = keytype;
set->keylen = keylen;
@@ -887,6 +887,8 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
set->set_flags |= SET_F_INTERVAL;
}
+ set->set_flags |= SET_F_CONSTANT;
+
set->dtype = ctx->ectx.dtype;
set->len = ctx->ectx.len;
set->flags |= EXPR_F_CONSTANT;
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH nft 2/6] set: explicitly supply name to implicit set declarations
2015-11-06 18:34 [RFC PATCH nft 0/6] flow statement Patrick McHardy
2015-11-06 18:34 ` [RFC PATCH nft 1/6] set: allow non-constant implicit set declarations Patrick McHardy
@ 2015-11-06 18:34 ` Patrick McHardy
2015-11-06 18:34 ` [RFC PATCH nft 3/6] netlink_delinearize: support parsing individual expressions not embedded in rules Patrick McHardy
` (5 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Patrick McHardy @ 2015-11-06 18:34 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Support explicitly named implicitly declared sets.
Also change the template names for literal sets and maps to use identifiers
that can not clash with user supplied identifiers.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
src/evaluate.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index f53ba5e..68d6bff 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -81,6 +81,7 @@ static int __fmtstring(3, 4) set_error(struct eval_ctx *ctx,
}
static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
+ const char *name,
const struct datatype *keytype,
unsigned int keylen,
struct expr *expr)
@@ -91,7 +92,7 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
set = set_alloc(&expr->location);
set->flags = SET_F_ANONYMOUS | expr->set_flags;
- set->handle.set = xstrdup(set->flags & SET_F_MAP ? "map%d" : "set%d");
+ set->handle.set = xstrdup(name),
set->keytype = keytype;
set->keylen = keylen;
set->init = expr;
@@ -912,7 +913,8 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
switch (map->mappings->ops->type) {
case EXPR_SET:
- mappings = implicit_set_declaration(ctx, ctx->ectx.dtype,
+ mappings = implicit_set_declaration(ctx, "__map%d",
+ ctx->ectx.dtype,
ctx->ectx.len, mappings);
mappings->set->datatype = ectx.dtype;
mappings->set->datalen = ectx.len;
@@ -1123,7 +1125,9 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
/* A literal set expression implicitly declares the set */
if (right->ops->type == EXPR_SET)
right = rel->right =
- implicit_set_declaration(ctx, left->dtype, left->len, right);
+ implicit_set_declaration(ctx, "__set%d",
+ left->dtype,
+ left->len, right);
else if (!datatype_equal(left->dtype, right->dtype))
return expr_binary_error(ctx->msgs, right, left,
"datatype mismatch, expected %s, "
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH nft 3/6] netlink_delinearize: support parsing individual expressions not embedded in rules
2015-11-06 18:34 [RFC PATCH nft 0/6] flow statement Patrick McHardy
2015-11-06 18:34 ` [RFC PATCH nft 1/6] set: allow non-constant implicit set declarations Patrick McHardy
2015-11-06 18:34 ` [RFC PATCH nft 2/6] set: explicitly supply name to " Patrick McHardy
@ 2015-11-06 18:34 ` Patrick McHardy
2015-11-06 18:34 ` [RFC PATCH nft 4/6] set_elem: parse expressions attached to set elements Patrick McHardy
` (4 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Patrick McHardy @ 2015-11-06 18:34 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
The flow statement contains a statement within the statement, in order to
parse it we need to return the parsed statement instead of adding it to
the rule list unconditionally.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
include/netlink.h | 2 +-
src/netlink_delinearize.c | 64 +++++++++++++++++++++++++++++------------------
2 files changed, 40 insertions(+), 26 deletions(-)
diff --git a/include/netlink.h b/include/netlink.h
index 8444742..c1def09 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -84,7 +84,7 @@ extern void netlink_linearize_rule(struct netlink_ctx *ctx,
struct nftnl_rule *nlr,
const struct rule *rule);
extern struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
- const struct nftnl_rule *r);
+ struct nftnl_rule *r);
extern int netlink_add_rule(struct netlink_ctx *ctx, const struct handle *h,
const struct rule *rule, uint32_t flags);
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 3584de7..97ac3ec 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -30,6 +30,7 @@ struct netlink_parse_ctx {
struct list_head *msgs;
struct table *table;
struct rule *rule;
+ struct stmt *stmt;
struct expr *registers[1 + NFT_REG32_15 - NFT_REG32_00 + 1];
};
@@ -167,7 +168,6 @@ static void netlink_parse_immediate(struct netlink_parse_ctx *ctx,
{
struct nft_data_delinearize nld;
enum nft_registers dreg;
- struct stmt *stmt;
struct expr *expr;
if (nftnl_expr_is_set(nle, NFTNL_EXPR_IMM_VERDICT)) {
@@ -183,10 +183,9 @@ static void netlink_parse_immediate(struct netlink_parse_ctx *ctx,
dreg = netlink_parse_register(nle, NFTNL_EXPR_IMM_DREG);
expr = netlink_alloc_data(loc, &nld, dreg);
- if (dreg == NFT_REG_VERDICT) {
- stmt = verdict_stmt_alloc(loc, expr);
- list_add_tail(&stmt->list, &ctx->rule->stmts);
- } else
+ if (dreg == NFT_REG_VERDICT)
+ ctx->stmt = verdict_stmt_alloc(loc, expr);
+ else
netlink_set_register(ctx, dreg, expr);
}
@@ -217,7 +216,6 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
struct nft_data_delinearize nld;
enum nft_registers sreg;
struct expr *expr, *left, *right;
- struct stmt *stmt;
enum ops op;
sreg = netlink_parse_register(nle, NFTNL_EXPR_CMP_SREG);
@@ -246,8 +244,7 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
}
expr = relational_expr_alloc(loc, op, left, right);
- stmt = expr_stmt_alloc(loc, expr);
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ ctx->stmt = expr_stmt_alloc(loc, expr);
}
static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
@@ -256,7 +253,6 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
{
enum nft_registers sreg, dreg;
const char *name;
- struct stmt *stmt;
struct expr *expr, *left, *right;
struct set *set;
@@ -290,8 +286,7 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
expr = relational_expr_alloc(loc, OP_LOOKUP, left, right);
}
- stmt = expr_stmt_alloc(loc, expr);
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ ctx->stmt = expr_stmt_alloc(loc, expr);
}
static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx,
@@ -467,7 +462,7 @@ static void netlink_parse_meta_stmt(struct netlink_parse_ctx *ctx,
stmt = meta_stmt_alloc(loc, key, expr);
expr_set_type(expr, stmt->meta.tmpl->dtype, stmt->meta.tmpl->byteorder);
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ ctx->stmt = stmt;
}
static void netlink_parse_meta(struct netlink_parse_ctx *ctx,
@@ -496,7 +491,7 @@ static void netlink_parse_ct_stmt(struct netlink_parse_ctx *ctx,
stmt = ct_stmt_alloc(loc, key, expr);
expr_set_type(expr, stmt->ct.tmpl->dtype, stmt->ct.tmpl->byteorder);
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ ctx->stmt = stmt;
}
static void netlink_parse_ct_expr(struct netlink_parse_ctx *ctx,
@@ -535,7 +530,8 @@ static void netlink_parse_counter(struct netlink_parse_ctx *ctx,
nftnl_expr_get_u64(nle, NFTNL_EXPR_CTR_PACKETS);
stmt->counter.bytes =
nftnl_expr_get_u64(nle, NFTNL_EXPR_CTR_BYTES);
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+
+ ctx->stmt = stmt;
}
static void netlink_parse_log(struct netlink_parse_ctx *ctx,
@@ -571,7 +567,8 @@ static void netlink_parse_log(struct netlink_parse_ctx *ctx,
nftnl_expr_get_u32(nle, NFTNL_EXPR_LOG_LEVEL);
stmt->log.flags |= STMT_LOG_LEVEL;
}
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+
+ ctx->stmt = stmt;
}
static void netlink_parse_limit(struct netlink_parse_ctx *ctx,
@@ -585,7 +582,8 @@ static void netlink_parse_limit(struct netlink_parse_ctx *ctx,
stmt->limit.unit = nftnl_expr_get_u64(nle, NFTNL_EXPR_LIMIT_UNIT);
stmt->limit.type = nftnl_expr_get_u32(nle, NFTNL_EXPR_LIMIT_TYPE);
stmt->limit.burst = nftnl_expr_get_u32(nle, NFTNL_EXPR_LIMIT_BURST);
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+
+ ctx->stmt = stmt;
}
static void netlink_parse_reject(struct netlink_parse_ctx *ctx,
@@ -602,7 +600,7 @@ static void netlink_parse_reject(struct netlink_parse_ctx *ctx,
stmt->reject.expr = constant_expr_alloc(loc, &integer_type,
BYTEORDER_HOST_ENDIAN, 8,
&icmp_code);
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ ctx->stmt = stmt;
}
static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
@@ -683,7 +681,7 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
stmt->nat.proto = proto;
}
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ ctx->stmt = stmt;
}
static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
@@ -700,7 +698,7 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
stmt = masq_stmt_alloc(loc);
stmt->masq.flags = flags;
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ ctx->stmt = stmt;
}
static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
@@ -746,7 +744,7 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
stmt->redir.proto = proto;
}
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ ctx->stmt = stmt;
}
static void netlink_parse_dup(struct netlink_parse_ctx *ctx,
@@ -792,7 +790,7 @@ static void netlink_parse_dup(struct netlink_parse_ctx *ctx,
stmt->dup.dev = dev;
}
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ ctx->stmt = stmt;
}
static void netlink_parse_queue(struct netlink_parse_ctx *ctx,
@@ -818,7 +816,8 @@ static void netlink_parse_queue(struct netlink_parse_ctx *ctx,
stmt = queue_stmt_alloc(loc);
stmt->queue.queue = expr;
stmt->queue.flags = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_FLAGS);
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+
+ ctx->stmt = stmt;
}
static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
@@ -858,7 +857,7 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
stmt->set.op = nftnl_expr_get_u32(nle, NFTNL_EXPR_DYNSET_OP);
stmt->set.key = expr;
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ ctx->stmt = stmt;
}
static const struct {
@@ -907,6 +906,21 @@ static int netlink_parse_expr(struct nftnl_expr *nle, void *arg)
}
netlink_error(ctx, &loc, "unknown expression type '%s'", type);
+ return -1;
+}
+
+static int netlink_parse_rule_expr(struct nftnl_expr *nle, void *arg)
+{
+ struct netlink_parse_ctx *ctx = arg;
+ int err;
+
+ err = netlink_parse_expr(nle, ctx);
+ if (err < 0)
+ return err;
+ if (ctx->stmt != NULL) {
+ list_add_tail(&ctx->stmt->list, &ctx->rule->stmts);
+ ctx->stmt = NULL;
+ }
return 0;
}
@@ -1592,7 +1606,7 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
}
struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
- const struct nftnl_rule *nlr)
+ struct nftnl_rule *nlr)
{
struct netlink_parse_ctx _ctx, *pctx = &_ctx;
struct handle h;
@@ -1622,7 +1636,7 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
pctx->rule = rule_alloc(&netlink_location, &h);
pctx->table = table_lookup(&h);
assert(pctx->table != NULL);
- nftnl_expr_foreach((struct nftnl_rule *)nlr, netlink_parse_expr, pctx);
+ nftnl_expr_foreach(nlr, netlink_parse_rule_expr, pctx);
rule_parse_postprocess(pctx, pctx->rule);
netlink_release_registers(pctx);
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH nft 4/6] set_elem: parse expressions attached to set elements
2015-11-06 18:34 [RFC PATCH nft 0/6] flow statement Patrick McHardy
` (2 preceding siblings ...)
2015-11-06 18:34 ` [RFC PATCH nft 3/6] netlink_delinearize: support parsing individual expressions not embedded in rules Patrick McHardy
@ 2015-11-06 18:34 ` Patrick McHardy
2015-11-11 12:37 ` Pablo Neira Ayuso
2015-11-06 18:34 ` [RFC PATCH nft 5/6] stmt: allow to generate stateful statements outside of rule context Patrick McHardy
` (3 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Patrick McHardy @ 2015-11-06 18:34 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Add support to parse and print expressions attached to set elements. This
is required for the flow statement, where expressions are dynamically
instantiated and attached to set elements.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
include/expression.h | 1 +
include/linux/netfilter/nf_tables.h | 2 ++
include/netlink.h | 3 +++
src/expression.c | 6 ++++++
src/netlink.c | 2 ++
src/netlink_delinearize.c | 12 ++++++++++++
6 files changed, 26 insertions(+)
diff --git a/include/expression.h b/include/expression.h
index 010cb95..e7f11eb 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -237,6 +237,7 @@ struct expr {
uint64_t timeout;
uint64_t expiration;
const char *comment;
+ struct stmt *stmt;
};
struct {
/* EXPR_UNARY */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 5ebe3d8..38ad174 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -321,6 +321,7 @@ enum nft_set_elem_flags {
* @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64)
* @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
+ * @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
*/
enum nft_set_elem_attributes {
NFTA_SET_ELEM_UNSPEC,
@@ -330,6 +331,7 @@ enum nft_set_elem_attributes {
NFTA_SET_ELEM_TIMEOUT,
NFTA_SET_ELEM_EXPIRATION,
NFTA_SET_ELEM_USERDATA,
+ NFTA_SET_ELEM_EXPR,
__NFTA_SET_ELEM_MAX
};
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
diff --git a/include/netlink.h b/include/netlink.h
index c1def09..018a573 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -149,6 +149,9 @@ extern int netlink_delete_setelems(struct netlink_ctx *ctx, const struct handle
extern int netlink_get_setelems(struct netlink_ctx *ctx, const struct handle *h,
const struct location *loc, struct set *set);
+extern struct stmt *netlink_parse_set_expr(struct set *set,
+ struct nftnl_expr *nle);
+
extern void netlink_dump_table(struct nftnl_table *nlt);
extern void netlink_dump_chain(struct nftnl_chain *nlc);
extern void netlink_dump_rule(struct nftnl_rule *nlr);
diff --git a/src/expression.c b/src/expression.c
index ab195e5..2c1ea6a 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -16,6 +16,7 @@
#include <limits.h>
#include <expression.h>
+#include <statement.h>
#include <datatype.h>
#include <rule.h>
#include <gmputil.h>
@@ -899,6 +900,11 @@ static void set_elem_expr_print(const struct expr *expr)
}
if (expr->comment)
printf(" comment \"%s\"", expr->comment);
+
+ if (expr->stmt) {
+ printf(" : ");
+ stmt_print(expr->stmt);
+ }
}
static void set_elem_expr_destroy(struct expr *expr)
diff --git a/src/netlink.c b/src/netlink.c
index ad86084..3bef5f4 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1472,6 +1472,8 @@ static int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
expr->comment = xmalloc(len);
memcpy((char *)expr->comment, data, len);
}
+ if (nftnl_set_elem_is_set(nlse, NFT_SET_ELEM_ATTR_EXPR))
+ expr->stmt = netlink_parse_set_expr(set, (void *)nftnl_set_elem_get(nlse, NFT_SET_ELEM_ATTR_EXPR, NULL));
if (flags & NFT_SET_ELEM_INTERVAL_END) {
expr->flags |= EXPR_F_INTERVAL_END;
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 97ac3ec..adeaccb 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -924,6 +924,18 @@ static int netlink_parse_rule_expr(struct nftnl_expr *nle, void *arg)
return 0;
}
+struct stmt *netlink_parse_set_expr(struct set *set, struct nftnl_expr *nle)
+{
+ struct netlink_parse_ctx ctx, *pctx = &ctx;
+
+ pctx->table = table_lookup(&set->handle);
+ assert(pctx->table != NULL);
+
+ if (netlink_parse_expr(nle, pctx) < 0)
+ return NULL;
+ return pctx->stmt;
+}
+
struct rule_pp_ctx {
struct proto_ctx pctx;
enum proto_bases pbase;
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [RFC PATCH nft 4/6] set_elem: parse expressions attached to set elements
2015-11-06 18:34 ` [RFC PATCH nft 4/6] set_elem: parse expressions attached to set elements Patrick McHardy
@ 2015-11-11 12:37 ` Pablo Neira Ayuso
2015-11-11 16:18 ` Patrick McHardy
0 siblings, 1 reply; 15+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-11 12:37 UTC (permalink / raw)
To: Patrick McHardy; +Cc: netfilter-devel
On Fri, Nov 06, 2015 at 06:34:21PM +0000, Patrick McHardy wrote:
> static void set_elem_expr_destroy(struct expr *expr)
> diff --git a/src/netlink.c b/src/netlink.c
> index ad86084..3bef5f4 100644
> --- a/src/netlink.c
> +++ b/src/netlink.c
> @@ -1472,6 +1472,8 @@ static int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
> expr->comment = xmalloc(len);
> memcpy((char *)expr->comment, data, len);
> }
> + if (nftnl_set_elem_is_set(nlse, NFT_SET_ELEM_ATTR_EXPR))
> + expr->stmt = netlink_parse_set_expr(set, (void *)nftnl_set_elem_get(nlse, NFT_SET_ELEM_ATTR_EXPR, NULL));
Minor nit I just noticed: please use NFTNL_SET_ELEM_EXPR here instead,
the old constant definitions will go after a couple of libnftnl
releases, they have been left there just to make the transition a bit
less traumatic.
Thanks.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC PATCH nft 4/6] set_elem: parse expressions attached to set elements
2015-11-11 12:37 ` Pablo Neira Ayuso
@ 2015-11-11 16:18 ` Patrick McHardy
0 siblings, 0 replies; 15+ messages in thread
From: Patrick McHardy @ 2015-11-11 16:18 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
On 11.11, Pablo Neira Ayuso wrote:
> On Fri, Nov 06, 2015 at 06:34:21PM +0000, Patrick McHardy wrote:
> > static void set_elem_expr_destroy(struct expr *expr)
> > diff --git a/src/netlink.c b/src/netlink.c
> > index ad86084..3bef5f4 100644
> > --- a/src/netlink.c
> > +++ b/src/netlink.c
> > @@ -1472,6 +1472,8 @@ static int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
> > expr->comment = xmalloc(len);
> > memcpy((char *)expr->comment, data, len);
> > }
> > + if (nftnl_set_elem_is_set(nlse, NFT_SET_ELEM_ATTR_EXPR))
> > + expr->stmt = netlink_parse_set_expr(set, (void *)nftnl_set_elem_get(nlse, NFT_SET_ELEM_ATTR_EXPR, NULL));
>
>
> Minor nit I just noticed: please use NFTNL_SET_ELEM_EXPR here instead,
> the old constant definitions will go after a couple of libnftnl
> releases, they have been left there just to make the transition a bit
> less traumatic.
Sure, fixed it. Thanks.
^ permalink raw reply [flat|nested] 15+ messages in thread
* [RFC PATCH nft 5/6] stmt: allow to generate stateful statements outside of rule context
2015-11-06 18:34 [RFC PATCH nft 0/6] flow statement Patrick McHardy
` (3 preceding siblings ...)
2015-11-06 18:34 ` [RFC PATCH nft 4/6] set_elem: parse expressions attached to set elements Patrick McHardy
@ 2015-11-06 18:34 ` Patrick McHardy
2015-11-06 18:34 ` [RFC PATCH nft 6/6] nft: add flow statement Patrick McHardy
` (2 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Patrick McHardy @ 2015-11-06 18:34 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
The flow statement contains a stateful statement within the statement,
special case stateful statements to return a pointer to the statement
so the caller can decide how to handle them.
Also mark stateful statements for flow statement validation.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
include/statement.h | 1 +
src/netlink_linearize.c | 90 +++++++++++++++++++++++++++++--------------------
src/statement.c | 12 +++++--
3 files changed, 65 insertions(+), 38 deletions(-)
diff --git a/include/statement.h b/include/statement.h
index 8b035d3..6a1001c 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -176,6 +176,7 @@ struct stmt_ops {
enum stmt_flags {
STMT_F_TERMINAL = 0x1,
+ STMT_F_STATEFUL = 0x2,
};
/**
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index c9af036..adcc559 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -663,23 +663,6 @@ static void netlink_gen_verdict_stmt(struct netlink_linearize_ctx *ctx,
return netlink_gen_expr(ctx, stmt->expr, NFT_REG_VERDICT);
}
-static void netlink_gen_counter_stmt(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
-{
- struct nftnl_expr *nle;
-
- nle = alloc_nft_expr("counter");
- if (stmt->counter.packets) {
- nftnl_expr_set_u64(nle, NFTNL_EXPR_CTR_PACKETS,
- stmt->counter.packets);
- }
- if (stmt->counter.bytes) {
- nftnl_expr_set_u64(nle, NFTNL_EXPR_CTR_BYTES,
- stmt->counter.bytes);
- }
- nftnl_rule_add_expr(ctx->nlr, nle);
-}
-
static void netlink_gen_meta_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
@@ -724,22 +707,6 @@ static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx,
nftnl_rule_add_expr(ctx->nlr, nle);
}
-static void netlink_gen_limit_stmt(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
-{
- struct nftnl_expr *nle;
-
- nle = alloc_nft_expr("limit");
- nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_RATE, stmt->limit.rate);
- nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_UNIT, stmt->limit.unit);
- nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_TYPE, stmt->limit.type);
- if (stmt->limit.burst > 0)
- nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_BURST,
- stmt->limit.burst);
-
- nftnl_rule_add_expr(ctx->nlr, nle);
-}
-
static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
@@ -980,22 +947,73 @@ static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
nftnl_rule_add_expr(ctx->nlr, nle);
}
+static struct nftnl_expr *
+netlink_gen_counter_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("counter");
+ if (stmt->counter.packets)
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_CTR_PACKETS,
+ stmt->counter.packets);
+ if (stmt->counter.bytes)
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_CTR_BYTES,
+ stmt->counter.bytes);
+
+ return nle;
+}
+
+static struct nftnl_expr *
+netlink_gen_limit_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("limit");
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_RATE, stmt->limit.rate);
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_UNIT, stmt->limit.unit);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_TYPE, stmt->limit.type);
+ if (stmt->limit.burst > 0)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_BURST,
+ stmt->limit.burst);
+
+ return nle;
+}
+
+static struct nftnl_expr *
+netlink_gen_stmt_stateful(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ switch (stmt->ops->type) {
+ case STMT_COUNTER:
+ return netlink_gen_counter_stmt(ctx, stmt);
+ case STMT_LIMIT:
+ return netlink_gen_limit_stmt(ctx, stmt);
+ default:
+ BUG("unknown statement type %s\n", stmt->ops->name);
+ }
+}
+
static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
+ struct nftnl_expr *nle;
+
switch (stmt->ops->type) {
case STMT_EXPRESSION:
return netlink_gen_expr(ctx, stmt->expr, NFT_REG_VERDICT);
case STMT_VERDICT:
return netlink_gen_verdict_stmt(ctx, stmt);
case STMT_COUNTER:
- return netlink_gen_counter_stmt(ctx, stmt);
+ case STMT_LIMIT:
+ nle = netlink_gen_stmt_stateful(ctx, stmt);
+ nftnl_rule_add_expr(ctx->nlr, nle);
+ return;
case STMT_META:
return netlink_gen_meta_stmt(ctx, stmt);
case STMT_LOG:
return netlink_gen_log_stmt(ctx, stmt);
- case STMT_LIMIT:
- return netlink_gen_limit_stmt(ctx, stmt);
case STMT_REJECT:
return netlink_gen_reject_stmt(ctx, stmt);
case STMT_NAT:
diff --git a/src/statement.c b/src/statement.c
index 2d1a3e6..55c9f15 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -117,7 +117,11 @@ static const struct stmt_ops counter_stmt_ops = {
struct stmt *counter_stmt_alloc(const struct location *loc)
{
- return stmt_alloc(loc, &counter_stmt_ops);
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &counter_stmt_ops);
+ stmt->flags |= STMT_F_STATEFUL;
+ return stmt;
}
static const char *syslog_level[LOG_DEBUG + 1] = {
@@ -246,7 +250,11 @@ static const struct stmt_ops limit_stmt_ops = {
struct stmt *limit_stmt_alloc(const struct location *loc)
{
- return stmt_alloc(loc, &limit_stmt_ops);
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &limit_stmt_ops);
+ stmt->flags |= STMT_F_STATEFUL;
+ return stmt;
}
static void queue_stmt_print(const struct stmt *stmt)
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* [RFC PATCH nft 6/6] nft: add flow statement
2015-11-06 18:34 [RFC PATCH nft 0/6] flow statement Patrick McHardy
` (4 preceding siblings ...)
2015-11-06 18:34 ` [RFC PATCH nft 5/6] stmt: allow to generate stateful statements outside of rule context Patrick McHardy
@ 2015-11-06 18:34 ` Patrick McHardy
2015-11-10 16:51 ` [RFC PATCH nft 0/6] " Pablo Neira Ayuso
2015-11-16 13:00 ` Pablo Neira Ayuso
7 siblings, 0 replies; 15+ messages in thread
From: Patrick McHardy @ 2015-11-06 18:34 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
The flow statement allows to dynmically instantiate stateful statements using
a user defined flow key. On the kernel side, the dynset statement is used and
the flows are maintained within dynamic sets and evaluated during instatiation
or lookup.
This allows f.i. to do something similar to hashlimit by instantiating the
limit statement per (arbitrary defined) flow:
nft filter input tcp dport ssh ct state new \
flow table ssh ip saddr limit 10/second
Or keep counters for arbitrary flows:
nft filter input flow \
table uidacct skuid . oid . ip protocol counter
Currently, the flow tables are displayed as normal sets. Before the final
version they will be moved to a more structured format which supports
sorting in multiple ways.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
include/linux/netfilter/nf_tables.h | 3 +++
include/rule.h | 1 +
include/statement.h | 12 ++++++++++++
src/evaluate.c | 34 +++++++++++++++++++++++++++++++++
src/netlink_delinearize.c | 34 ++++++++++++++++++++++++++++-----
src/netlink_linearize.c | 35 ++++++++++++++++++++++++++++++++++
src/parser_bison.y | 38 +++++++++++++++++++++++++++++++++++++
src/scanner.l | 2 ++
src/statement.c | 31 ++++++++++++++++++++++++++++++
9 files changed, 185 insertions(+), 5 deletions(-)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 38ad174..4909998 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -244,6 +244,7 @@ enum nft_set_flags {
NFT_SET_INTERVAL = 0x4,
NFT_SET_MAP = 0x8,
NFT_SET_TIMEOUT = 0x10,
+ NFT_SET_EVAL = 0x20,
};
/**
@@ -564,6 +565,7 @@ enum nft_dynset_ops {
* @NFTA_DYNSET_SREG_KEY: source register of the key (NLA_U32)
* @NFTA_DYNSET_SREG_DATA: source register of the data (NLA_U32)
* @NFTA_DYNSET_TIMEOUT: timeout value for the new element (NLA_U64)
+ * @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes)
*/
enum nft_dynset_attributes {
NFTA_DYNSET_UNSPEC,
@@ -573,6 +575,7 @@ enum nft_dynset_attributes {
NFTA_DYNSET_SREG_KEY,
NFTA_DYNSET_SREG_DATA,
NFTA_DYNSET_TIMEOUT,
+ NFTA_DYNSET_EXPR,
__NFTA_DYNSET_MAX,
};
#define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1)
diff --git a/include/rule.h b/include/rule.h
index a86f600..393ada8 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -183,6 +183,7 @@ enum set_flags {
SET_F_INTERVAL = 0x4,
SET_F_MAP = 0x8,
SET_F_TIMEOUT = 0x10,
+ SET_F_EVAL = 0x20,
};
/**
diff --git a/include/statement.h b/include/statement.h
index 6a1001c..e3f9a1c 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -121,12 +121,22 @@ struct set_stmt {
extern struct stmt *set_stmt_alloc(const struct location *loc);
+struct flow_stmt {
+ struct expr *set;
+ struct expr *key;
+ struct stmt *stmt;
+ const char *table;
+};
+
+extern struct stmt *flow_stmt_alloc(const struct location *loc);
+
/**
* enum stmt_types - statement types
*
* @STMT_INVALID: uninitialised
* @STMT_EXPRESSION: expression statement (relational)
* @STMT_VERDICT: verdict statement
+ * @STMT_FLOW: flow statement
* @STMT_COUNTER: counters
* @STMT_META: meta statement
* @STMT_LIMIT: limit statement
@@ -144,6 +154,7 @@ enum stmt_types {
STMT_INVALID,
STMT_EXPRESSION,
STMT_VERDICT,
+ STMT_FLOW,
STMT_COUNTER,
STMT_META,
STMT_LIMIT,
@@ -196,6 +207,7 @@ struct stmt {
union {
struct expr *expr;
+ struct flow_stmt flow;
struct counter_stmt counter;
struct meta_stmt meta;
struct log_stmt log;
diff --git a/src/evaluate.c b/src/evaluate.c
index 68d6bff..0d8a13a 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1348,6 +1348,38 @@ static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt)
return 0;
}
+static int stmt_evaluate_flow(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct expr *key, *set, *setref;
+
+ expr_set_context(&ctx->ectx, NULL, 0);
+ if (expr_evaluate(ctx, &stmt->flow.key) < 0)
+ return -1;
+ if (expr_is_constant(stmt->flow.key))
+ return expr_error(ctx->msgs, stmt->flow.key,
+ "Flow key expression can not be constant");
+
+ if (!(stmt->flow.stmt->flags & STMT_F_STATEFUL))
+ return stmt_binary_error(ctx, stmt->flow.stmt, stmt,
+ "Flow statement can only be used with "
+ "stateful statements");
+
+ /* Declare an empty set */
+ key = stmt->flow.key;
+ set = set_expr_alloc(&key->location);
+ set->set_flags |= SET_F_EVAL;
+ if (key->timeout)
+ set->set_flags |= SET_F_TIMEOUT;
+ setref = implicit_set_declaration(ctx, stmt->flow.table ?: "__ft%d",
+ key->dtype, key->len, set);
+
+ stmt->flow.set = setref;
+
+ if (stmt_evaluate(ctx, stmt->flow.stmt) < 0)
+ return -1;
+ return 0;
+}
+
static int stmt_evaluate_meta(struct eval_ctx *ctx, struct stmt *stmt)
{
return stmt_evaluate_arg(ctx, stmt,
@@ -1911,6 +1943,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
return stmt_evaluate_expr(ctx, stmt);
case STMT_VERDICT:
return stmt_evaluate_verdict(ctx, stmt);
+ case STMT_FLOW:
+ return stmt_evaluate_flow(ctx, stmt);
case STMT_META:
return stmt_evaluate_meta(ctx, stmt);
case STMT_CT:
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index adeaccb..a47f7ca 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -34,6 +34,8 @@ struct netlink_parse_ctx {
struct expr *registers[1 + NFT_REG32_15 - NFT_REG32_00 + 1];
};
+static int netlink_parse_expr(struct nftnl_expr *nle, void *arg);
+
static void __fmtstring(3, 4) netlink_error(struct netlink_parse_ctx *ctx,
const struct location *loc,
const char *fmt, ...)
@@ -824,8 +826,9 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
{
+ const struct nftnl_expr *dnle;
struct expr *expr;
- struct stmt *stmt;
+ struct stmt *stmt, *dstmt;
struct set *set;
enum nft_registers sreg;
const char *name;
@@ -852,10 +855,28 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
expr = set_elem_expr_alloc(&expr->location, expr);
expr->timeout = nftnl_expr_get_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT);
- stmt = set_stmt_alloc(loc);
- stmt->set.set = set_ref_expr_alloc(loc, set);
- stmt->set.op = nftnl_expr_get_u32(nle, NFTNL_EXPR_DYNSET_OP);
- stmt->set.key = expr;
+ dstmt = NULL;
+ dnle = nftnl_expr_get(nle, NFT_EXPR_DYNSET_EXPR, NULL);
+ if (dnle != NULL) {
+ if (netlink_parse_expr((void *)dnle, ctx) < 0)
+ return;
+ if (ctx->stmt == NULL)
+ return netlink_error(ctx, loc,
+ "Could not parse dynset stmt");
+ dstmt = ctx->stmt;
+ }
+
+ if (dstmt != NULL) {
+ stmt = flow_stmt_alloc(loc);
+ stmt->flow.set = set_ref_expr_alloc(loc, set);
+ stmt->flow.key = expr;
+ stmt->flow.stmt = dstmt;
+ } else {
+ stmt = set_stmt_alloc(loc);
+ stmt->set.set = set_ref_expr_alloc(loc, set);
+ stmt->set.op = nftnl_expr_get_u32(nle, NFTNL_EXPR_DYNSET_OP);
+ stmt->set.key = expr;
+ }
ctx->stmt = stmt;
}
@@ -1604,6 +1625,9 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
case STMT_SET:
expr_postprocess(&rctx, &stmt->set.key);
break;
+ case STMT_FLOW:
+ expr_postprocess(&rctx, &stmt->flow.key);
+ break;
case STMT_DUP:
if (stmt->dup.to != NULL)
expr_postprocess(&rctx, &stmt->dup.to);
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index adcc559..0f4b31e 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -995,6 +995,39 @@ netlink_gen_stmt_stateful(struct netlink_linearize_ctx *ctx,
}
}
+static void netlink_gen_flow_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle, *dnle;
+ enum nft_registers sreg_key;
+ enum nft_dynset_ops op;
+
+ sreg_key = get_register(ctx, stmt->flow.key);
+ netlink_gen_expr(ctx, stmt->flow.key, sreg_key);
+ release_register(ctx, stmt->flow.key);
+
+ if (stmt->flow.key->timeout)
+ op = NFT_DYNSET_OP_UPDATE;
+ else
+ op = NFT_DYNSET_OP_ADD;
+
+ nle = alloc_nft_expr("dynset");
+ netlink_put_register(nle, NFT_EXPR_DYNSET_SREG_KEY, sreg_key);
+ if (stmt->flow.key->timeout)
+ nftnl_expr_set_u64(nle, NFT_EXPR_DYNSET_TIMEOUT,
+ stmt->flow.key->timeout);
+ nftnl_expr_set_u32(nle, NFT_EXPR_DYNSET_OP, op);
+ nftnl_expr_set_str(nle, NFT_EXPR_DYNSET_SET_NAME,
+ stmt->flow.set->set->handle.set);
+ nftnl_expr_set_u32(nle, NFT_EXPR_DYNSET_SET_ID,
+ stmt->flow.set->set->handle.set_id);
+
+ dnle = netlink_gen_stmt_stateful(ctx, stmt->flow.stmt);
+ nftnl_expr_set(nle, NFT_EXPR_DYNSET_EXPR, dnle, 0);
+
+ nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
@@ -1005,6 +1038,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
return netlink_gen_expr(ctx, stmt->expr, NFT_REG_VERDICT);
case STMT_VERDICT:
return netlink_gen_verdict_stmt(ctx, stmt);
+ case STMT_FLOW:
+ return netlink_gen_flow_stmt(ctx, stmt);
case STMT_COUNTER:
case STMT_LIMIT:
nle = netlink_gen_stmt_stateful(ctx, stmt);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index ab4524b..8049b4a 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -214,6 +214,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token PERFORMANCE "performance"
%token SIZE "size"
+%token FLOW "flow"
+
%token <val> NUM "number"
%token <string> STRING "string"
%token <string> QUOTED_STRING
@@ -470,6 +472,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <stmt> set_stmt
%destructor { stmt_free($$); } set_stmt
%type <val> set_stmt_op
+%type <stmt> flow_stmt flow_stmt_alloc
+%destructor { stmt_free($$); } flow_stmt flow_stmt_alloc
%type <expr> symbol_expr verdict_expr integer_expr
%destructor { expr_free($$); } symbol_expr verdict_expr integer_expr
@@ -1311,6 +1315,7 @@ stmt_list : stmt
stmt : verdict_stmt
| match_stmt
+ | flow_stmt
| counter_stmt
| meta_stmt
| log_stmt
@@ -1697,6 +1702,39 @@ set_stmt_op : ADD { $$ = NFT_DYNSET_OP_ADD; }
| UPDATE { $$ = NFT_DYNSET_OP_UPDATE; }
;
+flow_stmt : flow_stmt_alloc flow_stmt_opts set_elem_expr stmt
+ {
+ $1->flow.key = $3;
+ $1->flow.stmt = $4;
+ $$ = $1;
+ }
+ | flow_stmt_alloc set_elem_expr stmt
+ {
+ $1->flow.key = $2;
+ $1->flow.stmt = $3;
+ $$ = $1;
+ }
+ ;
+
+flow_stmt_alloc : FLOW
+ {
+ $$ = flow_stmt_alloc(&@$);
+ }
+ ;
+
+flow_stmt_opts : flow_stmt_opt
+ {
+ $<stmt>$ = $<stmt>0;
+ }
+ | flow_stmt_opts flow_stmt_opt
+ ;
+
+flow_stmt_opt : TABLE identifier
+ {
+ $<stmt>0->flow.table = $2;
+ }
+ ;
+
match_stmt : relational_expr
{
$$ = expr_stmt_alloc(&@$, $1);
diff --git a/src/scanner.l b/src/scanner.l
index a98e7b6..4a886d9 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -285,6 +285,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"performance" { return PERFORMANCE; }
"memory" { return MEMORY; }
+"flow" { return FLOW; }
+
"counter" { return COUNTER; }
"packets" { return PACKETS; }
"bytes" { return BYTES; }
diff --git a/src/statement.c b/src/statement.c
index 55c9f15..e721706 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -21,6 +21,7 @@
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <statement.h>
+#include <rule.h>
#include <utils.h>
#include <list.h>
@@ -41,6 +42,8 @@ struct stmt *stmt_alloc(const struct location *loc,
void stmt_free(struct stmt *stmt)
{
+ if (stmt == NULL)
+ return;
if (stmt->ops->destroy)
stmt->ops->destroy(stmt);
xfree(stmt);
@@ -103,6 +106,34 @@ struct stmt *verdict_stmt_alloc(const struct location *loc, struct expr *expr)
return stmt;
}
+static void flow_stmt_print(const struct stmt *stmt)
+{
+ printf("flow ");
+ if (stmt->flow.set)
+ printf("table %s ", stmt->flow.set->set->handle.set);
+ expr_print(stmt->flow.key);
+ printf(" ");
+ stmt_print(stmt->flow.stmt);
+}
+
+static void flow_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->flow.key);
+ stmt_free(stmt->flow.stmt);
+}
+
+static const struct stmt_ops flow_stmt_ops = {
+ .type = STMT_FLOW,
+ .name = "flow",
+ .print = flow_stmt_print,
+ .destroy = flow_stmt_destroy,
+};
+
+struct stmt *flow_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &flow_stmt_ops);
+}
+
static void counter_stmt_print(const struct stmt *stmt)
{
printf("counter packets %" PRIu64 " bytes %" PRIu64,
--
2.4.3
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [RFC PATCH nft 0/6] flow statement
2015-11-06 18:34 [RFC PATCH nft 0/6] flow statement Patrick McHardy
` (5 preceding siblings ...)
2015-11-06 18:34 ` [RFC PATCH nft 6/6] nft: add flow statement Patrick McHardy
@ 2015-11-10 16:51 ` Pablo Neira Ayuso
2015-11-10 17:59 ` Bjørnar Ness
2015-11-10 18:22 ` Patrick McHardy
2015-11-16 13:00 ` Pablo Neira Ayuso
7 siblings, 2 replies; 15+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-10 16:51 UTC (permalink / raw)
To: Patrick McHardy; +Cc: netfilter-devel
Hi Patrick,
On Fri, Nov 06, 2015 at 06:34:17PM +0000, Patrick McHardy wrote:
> The following patches add support for the flow statement, which allows to
> dynamically instantiate stateful statements fow an arbitrary defined flow
> key.
>
> Currently we have to stateful statements, counter and limit. This example
> shows some accounting possibilities using the counter statement. Please note
> that the output format is still WIP and not included in this patchset:
>
> # nft filter input flow table test iif . tcp flags counter
This looks very good to me :-).
> # nft list flow table filter test
> iface_index tcp_flag statement
> lo fin | psh | urg counter packets 1002 bytes 40080
> wlp2s0 fin | ack counter packets 3 bytes 156
> wlp2s0 ack counter packets 32 bytes 18440
> wlp2s0 syn | ack counter packets 5 bytes 300
> wlp2s0 psh | ack counter packets 57 bytes 13804
> lo rst | ack counter packets 998 bytes 39920
>
> # nft filter output flow table uidacct skuid . oif . ip protocol counter
> # nft list flow table filter uidacct
BTW, I can see the content is currently listed (in the non-pretty
output format) through:
nft list set filter test
so I can see how that flow table gets populated with entries.
>From the syntax perspective, I'm aware this the general definition in
the industry for this is 'flow table' but my only concern here with
this denomination is that we already have in our own tables with quite
different semantics.
Moreover, the fact that we can list this as sets (since they are
actually using the generic nf_tables set infrastructure) may be
confusing to users.
BTW, should we have implicit and explicit flow tables just like sets?
Thanks!
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [RFC PATCH nft 0/6] flow statement
2015-11-10 16:51 ` [RFC PATCH nft 0/6] " Pablo Neira Ayuso
@ 2015-11-10 17:59 ` Bjørnar Ness
2015-11-10 18:23 ` Patrick McHardy
2015-11-10 18:22 ` Patrick McHardy
1 sibling, 1 reply; 15+ messages in thread
From: Bjørnar Ness @ 2015-11-10 17:59 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Patrick McHardy, netfilter-devel
System hangs here if I do the following:
add a flow table
list flowtable, cant make nft list flow table work, so do nft list set
filter test
flush rules and change flowtable concat, for example adding . ip saddr
everything seemingly fine this far, but if I now list set filter test,
system becomes
unresponsive, and a boot seems needed.
Kernel is 4.3.0 and latest libnftnl/nftables git with the 1-6
flowtable patches applied.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC PATCH nft 0/6] flow statement
2015-11-10 17:59 ` Bjørnar Ness
@ 2015-11-10 18:23 ` Patrick McHardy
2015-11-10 18:26 ` Pablo Neira Ayuso
0 siblings, 1 reply; 15+ messages in thread
From: Patrick McHardy @ 2015-11-10 18:23 UTC (permalink / raw)
To: Bjørnar Ness; +Cc: Pablo Neira Ayuso, netfilter-devel
On 10.11, Bjørnar Ness wrote:
> System hangs here if I do the following:
>
> add a flow table
>
> list flowtable, cant make nft list flow table work, so do nft list set
> filter test
>
> flush rules and change flowtable concat, for example adding . ip saddr
>
> everything seemingly fine this far, but if I now list set filter test,
> system becomes
> unresponsive, and a boot seems needed.
Please provide the exact commands you used.
--
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] 15+ messages in thread
* Re: [RFC PATCH nft 0/6] flow statement
2015-11-10 18:23 ` Patrick McHardy
@ 2015-11-10 18:26 ` Pablo Neira Ayuso
0 siblings, 0 replies; 15+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-10 18:26 UTC (permalink / raw)
To: Bjørnar Ness; +Cc: netfilter-devel, Patrick McHardy
On Tue, Nov 10, 2015 at 06:23:45PM +0000, Patrick McHardy wrote:
> On 10.11, Bjørnar Ness wrote:
> > System hangs here if I do the following:
> >
> > add a flow table
> >
> > list flowtable, cant make nft list flow table work, so do nft list set
> > filter test
> >
> > flush rules and change flowtable concat, for example adding . ip saddr
> >
> > everything seemingly fine this far, but if I now list set filter test,
> > system becomes
> > unresponsive, and a boot seems needed.
>
> Please provide the exact commands you used.
If you using counters, the patches I just posted should resolve the
problem.
--
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] 15+ messages in thread
* Re: [RFC PATCH nft 0/6] flow statement
2015-11-10 16:51 ` [RFC PATCH nft 0/6] " Pablo Neira Ayuso
2015-11-10 17:59 ` Bjørnar Ness
@ 2015-11-10 18:22 ` Patrick McHardy
1 sibling, 0 replies; 15+ messages in thread
From: Patrick McHardy @ 2015-11-10 18:22 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: netfilter-devel
On 10.11, Pablo Neira Ayuso wrote:
> Hi Patrick,
>
> On Fri, Nov 06, 2015 at 06:34:17PM +0000, Patrick McHardy wrote:
> > The following patches add support for the flow statement, which allows to
> > dynamically instantiate stateful statements fow an arbitrary defined flow
> > key.
> >
> > Currently we have to stateful statements, counter and limit. This example
> > shows some accounting possibilities using the counter statement. Please note
> > that the output format is still WIP and not included in this patchset:
> >
> > # nft filter input flow table test iif . tcp flags counter
>
> This looks very good to me :-).
>
> > # nft list flow table filter test
> > iface_index tcp_flag statement
> > lo fin | psh | urg counter packets 1002 bytes 40080
> > wlp2s0 fin | ack counter packets 3 bytes 156
> > wlp2s0 ack counter packets 32 bytes 18440
> > wlp2s0 syn | ack counter packets 5 bytes 300
> > wlp2s0 psh | ack counter packets 57 bytes 13804
> > lo rst | ack counter packets 998 bytes 39920
> >
> > # nft filter output flow table uidacct skuid . oif . ip protocol counter
> > # nft list flow table filter uidacct
>
> BTW, I can see the content is currently listed (in the non-pretty
> output format) through:
>
> nft list set filter test
>
> so I can see how that flow table gets populated with entries.
Yes, for now this is not explicitly surpressed.
> >From the syntax perspective, I'm aware this the general definition in
> the industry for this is 'flow table' but my only concern here with
> this denomination is that we already have in our own tables with quite
> different semantics.
You mean our rule tables? Yeah, but this is explicitly qualified as
"flow" table. I don't really think there is much room for confusion.
I'm open to suggestions of course.
> Moreover, the fact that we can list this as sets (since they are
> actually using the generic nf_tables set infrastructure) may be
> confusing to users.
That is only until we have explicit listing for these. I'll hide them
from the set view then.
> BTW, should we have implicit and explicit flow tables just like sets?
So far explicit flow tables don't make sense since the kernel enforces
that only a single binding exists. I've added this since the desired
semantics of shared flow tables have to be hashed out first and I didn't
want to commit to something without thinking it through.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC PATCH nft 0/6] flow statement
2015-11-06 18:34 [RFC PATCH nft 0/6] flow statement Patrick McHardy
` (6 preceding siblings ...)
2015-11-10 16:51 ` [RFC PATCH nft 0/6] " Pablo Neira Ayuso
@ 2015-11-16 13:00 ` Pablo Neira Ayuso
7 siblings, 0 replies; 15+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-16 13:00 UTC (permalink / raw)
To: Patrick McHardy; +Cc: netfilter-devel
Hi Patrick,
On Fri, Nov 06, 2015 at 06:34:17PM +0000, Patrick McHardy wrote:
> # nft filter input flow table test iif . tcp flags counter
> # nft filter output flow table uidacct skuid . oif . ip protocol counter
Probably we can enclose the table definition in brackets? ie.
# nft filter output flow table uidacct { skuid . oif . ip protocol counter }
Thus the user becomes aware that any follow up statement applies
globally to the rule.
At this stage we only have one expression, but maybe in the future we
extend the flow table to support more that one stateful expression,
then we may have problems with this syntax.
Let me know, thanks.
^ permalink raw reply [flat|nested] 15+ messages in thread