* [PATCH 00/10] nftables: set timeouts and dynamic updates
@ 2015-04-12 12:16 Patrick McHardy
2015-04-12 12:16 ` [PATCH 01/10] datatype: fix parsing of time type Patrick McHardy
` (9 more replies)
0 siblings, 10 replies; 11+ messages in thread
From: Patrick McHardy @ 2015-04-12 12:16 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
The following patches contain support for the new features that have
already been merged to net-next, namely
* set and set element timeouts
* set element comments
* dynamic set updates
The first patch fixes parsing of the time time, the second one relaxes
time parsing. The third and fourth patches add support for time
specification as parameters to the grammar.
The fifth patch fixes inconsistencies in the set greammar, the six
patch adds a generic set element that will be used to attach element
attributes to expressions.
Finally, the seventh patch adds support for set timeouts, the eighth
patch for set element timeouts, the ninth for set element comments.
The last patch adds support for the "set" statement for dynamic set
updates.
I'll give them some more testing and will then push them to a -next
branch in the nftables tree.
Comments, especially regarding the syntax, are welcome.
Patrick McHardy (10):
datatype: fix parsing of time type
datatype: less strict time parsing
datatype: seperate time parsing/printing from time_type
parser: add a time_spec rule
parser: fix inconsistencies in set expression rules
expr: add set_elem_expr as container for set element attributes
set: add timeout support for sets
setelem: add timeout support for set elements
setelem: add support for attaching comments to set elements
nftables: add set statement
include/datatype.h | 4 ++
include/expression.h | 11 ++++
include/linux/netfilter/nf_tables.h | 39 ++++++++++++++
include/rule.h | 5 ++
include/statement.h | 11 ++++
src/datatype.c | 82 ++++++++++++++--------------
src/evaluate.c | 47 +++++++++++++++-
src/expression.c | 42 +++++++++++++++
src/netlink.c | 83 +++++++++++++++++++---------
src/netlink_delinearize.c | 41 ++++++++++++++
src/netlink_linearize.c | 26 +++++++++
src/parser_bison.y | 105 +++++++++++++++++++++++++++++++-----
src/rule.c | 23 +++++++-
src/scanner.l | 10 ++++
src/segtree.c | 8 ++-
src/statement.c | 31 +++++++++++
16 files changed, 486 insertions(+), 82 deletions(-)
--
2.1.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 01/10] datatype: fix parsing of time type
2015-04-12 12:16 [PATCH 00/10] nftables: set timeouts and dynamic updates Patrick McHardy
@ 2015-04-12 12:16 ` Patrick McHardy
2015-04-12 12:16 ` [PATCH 02/10] datatype: less strict time parsing Patrick McHardy
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2015-04-12 12:16 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Properly detect time strings in the lexer without quotation marks.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
src/datatype.c | 4 ----
src/scanner.l | 7 +++++++
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/datatype.c b/src/datatype.c
index c93f76a..0772b50 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -775,8 +775,6 @@ static void time_type_print(const struct expr *expr)
minutes = seconds / 60;
seconds %= 60;
- printf("\"");
-
if (days > 0)
printf("%"PRIu64"d", days);
if (hours > 0)
@@ -785,8 +783,6 @@ static void time_type_print(const struct expr *expr)
printf("%"PRIu64"m", minutes);
if (seconds > 0)
printf("%"PRIu64"s", seconds);
-
- printf("\"");
}
enum {
diff --git a/src/scanner.l b/src/scanner.l
index 73c4f8b..27d95bf 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -117,6 +117,8 @@ quotedstring \"[^"]*\"
comment #.*$
slash \/
+timestring ([0-9]+d)?([0-9]+h)?([0-9]+m)?([0-9]+s)?
+
hex4 ([[:xdigit:]]{1,4})
v680 (({hex4}:){7}{hex4})
v670 ((:)((:{hex4}){7}))
@@ -457,6 +459,11 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
return STRING;
}
+{timestring} {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+
{decstring} {
errno = 0;
yylval->val = strtoull(yytext, NULL, 0);
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 02/10] datatype: less strict time parsing
2015-04-12 12:16 [PATCH 00/10] nftables: set timeouts and dynamic updates Patrick McHardy
2015-04-12 12:16 ` [PATCH 01/10] datatype: fix parsing of time type Patrick McHardy
@ 2015-04-12 12:16 ` Patrick McHardy
2015-04-12 12:16 ` [PATCH 03/10] datatype: seperate time parsing/printing from time_type Patrick McHardy
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2015-04-12 12:16 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Don't require hours to be in range 0-23 and minutes/seconds in range 0-59.
The time_type is used for relative times where it is entirely reasonable
to specify 180s instead of 3m.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
src/datatype.c | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/src/datatype.c b/src/datatype.c
index 0772b50..1c83715 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -831,10 +831,6 @@ static struct error_record *time_type_parse(const struct expr *sym,
}
h = str2int(tmp, c, k);
k = 0;
- if (h > 23) {
- return error(&sym->location,
- "Hour needs to be 0-23");
- }
mask |= HOUR;
break;
case 'm':
@@ -844,10 +840,6 @@ static struct error_record *time_type_parse(const struct expr *sym,
}
m = str2int(tmp, c, k);
k = 0;
- if (m > 59) {
- return error(&sym->location,
- "Minute needs to be 0-59");
- }
mask |= MIN;
break;
case 's':
@@ -857,10 +849,6 @@ static struct error_record *time_type_parse(const struct expr *sym,
}
s = str2int(tmp, c, k);
k = 0;
- if (s > 59) {
- return error(&sym->location,
- "second needs to be 0-59");
- }
mask |= SECS;
break;
default:
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 03/10] datatype: seperate time parsing/printing from time_type
2015-04-12 12:16 [PATCH 00/10] nftables: set timeouts and dynamic updates Patrick McHardy
2015-04-12 12:16 ` [PATCH 01/10] datatype: fix parsing of time type Patrick McHardy
2015-04-12 12:16 ` [PATCH 02/10] datatype: less strict time parsing Patrick McHardy
@ 2015-04-12 12:16 ` Patrick McHardy
2015-04-12 12:16 ` [PATCH 04/10] parser: add a time_spec rule Patrick McHardy
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2015-04-12 12:16 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Seperate relative time parsing and printing from the time_type to make
it usable for set and set element time related parameters.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
include/datatype.h | 4 ++++
src/datatype.c | 66 +++++++++++++++++++++++++++++++++---------------------
2 files changed, 45 insertions(+), 25 deletions(-)
diff --git a/include/datatype.h b/include/datatype.h
index 3c3f42f..2a6a4fc 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -231,4 +231,8 @@ concat_subtype_lookup(uint32_t type, unsigned int n)
return datatype_lookup(concat_subtype_id(type, n));
}
+extern void time_print(uint64_t seconds);
+extern struct error_record *time_parse(const struct location *loc,
+ const char *c, uint64_t *res);
+
#endif /* NFTABLES_DATATYPE_H */
diff --git a/src/datatype.c b/src/datatype.c
index 1c83715..f93337b 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -760,11 +760,9 @@ const struct datatype icmpx_code_type = {
.sym_tbl = &icmpx_code_tbl,
};
-static void time_type_print(const struct expr *expr)
+void time_print(uint64_t seconds)
{
- uint64_t days, hours, minutes, seconds;
-
- seconds = mpz_get_uint64(expr->value);
+ uint64_t days, hours, minutes;
days = seconds / 86400;
seconds %= 86400;
@@ -801,8 +799,8 @@ static uint32_t str2int(char *tmp, const char *c, int k)
return atoi(tmp);
}
-static struct error_record *time_type_parse(const struct expr *sym,
- struct expr **res)
+struct error_record *time_parse(const struct location *loc, const char *str,
+ uint64_t *res)
{
int i, len;
unsigned int k = 0;
@@ -811,64 +809,82 @@ static struct error_record *time_type_parse(const struct expr *sym,
uint64_t d = 0, h = 0, m = 0, s = 0;
uint32_t mask = 0;
- c = sym->identifier;
+ c = str;
len = strlen(c);
for (i = 0; i < len; i++, c++) {
switch (*c) {
case 'd':
- if (mask & DAY) {
- return error(&sym->location,
+ if (mask & DAY)
+ return error(loc,
"Day has been specified twice");
- }
+
d = str2int(tmp, c, k);
k = 0;
mask |= DAY;
break;
case 'h':
- if (mask & HOUR) {
- return error(&sym->location,
+ if (mask & HOUR)
+ return error(loc,
"Hour has been specified twice");
- }
+
h = str2int(tmp, c, k);
k = 0;
mask |= HOUR;
break;
case 'm':
- if (mask & MIN) {
- return error(&sym->location,
+ if (mask & MIN)
+ return error(loc,
"Minute has been specified twice");
- }
+
m = str2int(tmp, c, k);
k = 0;
mask |= MIN;
break;
case 's':
- if (mask & SECS) {
- return error(&sym->location,
+ if (mask & SECS)
+ return error(loc,
"Second has been specified twice");
- }
+
s = str2int(tmp, c, k);
k = 0;
mask |= SECS;
break;
default:
if (!isdigit(*c))
- return error(&sym->location, "wrong format");
+ return error(loc, "wrong time format");
- if (k++ >= array_size(tmp)) {
- return error(&sym->location,
- "value too large");
- }
+ if (k++ >= array_size(tmp))
+ return error(loc, "value too large");
break;
}
}
/* default to seconds if no unit was specified */
if (!mask)
- s = atoi(sym->identifier);
+ s = atoi(str);
else
s = 24*60*60*d+60*60*h+60*m+s;
+ *res = s;
+ return NULL;
+}
+
+
+static void time_type_print(const struct expr *expr)
+{
+ time_print(mpz_get_uint64(expr->value));
+}
+
+static struct error_record *time_type_parse(const struct expr *sym,
+ struct expr **res)
+{
+ struct error_record *erec;
+ uint64_t s;
+
+ erec = time_parse(&sym->location, sym->identifier, &s);
+ if (erec != NULL)
+ return erec;
+
if (s > UINT32_MAX)
return error(&sym->location, "value too large");
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 04/10] parser: add a time_spec rule
2015-04-12 12:16 [PATCH 00/10] nftables: set timeouts and dynamic updates Patrick McHardy
` (2 preceding siblings ...)
2015-04-12 12:16 ` [PATCH 03/10] datatype: seperate time parsing/printing from time_type Patrick McHardy
@ 2015-04-12 12:16 ` Patrick McHardy
2015-04-12 12:16 ` [PATCH 05/10] parser: fix inconsistencies in set expression rules Patrick McHardy
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2015-04-12 12:16 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
src/parser_bison.y | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index b86381d..cd4e096 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -396,6 +396,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <string> identifier string comment_spec
%destructor { xfree($$); } identifier string comment_spec
+%type <val> time_spec
+
%type <val> type_identifier
%type <datatype> data_type
@@ -1093,6 +1095,20 @@ string : STRING
| QUOTED_STRING
;
+time_spec : STRING
+ {
+ struct error_record *erec;
+ uint64_t res;
+
+ erec = time_parse(&@1, $1, &res);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ $$ = res;
+ }
+ ;
+
family_spec : /* empty */ { $$ = NFPROTO_IPV4; }
| family_spec_explicit
;
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 05/10] parser: fix inconsistencies in set expression rules
2015-04-12 12:16 [PATCH 00/10] nftables: set timeouts and dynamic updates Patrick McHardy
` (3 preceding siblings ...)
2015-04-12 12:16 ` [PATCH 04/10] parser: add a time_spec rule Patrick McHardy
@ 2015-04-12 12:16 ` Patrick McHardy
2015-04-12 12:16 ` [PATCH 06/10] expr: add set_elem_expr as container for set element attributes Patrick McHardy
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2015-04-12 12:16 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Set keys are currently defined as a regular expr for pure sets and
map_lhs_expr for maps. map_lhs_expr is what can actually be used for
a single member, namely a concat_expr or a multiton_expr. The reason
why pure sets use expr for the key is to allow recursive set specifications,
which doesn't make sense for maps since every element needs a mapping.
However, the rule is too wide and also allows map expressions as a key,
which obviously doesn't make sense.
Rearrange the rules so we have:
set_lhs_expr: concat or multiton
set_rhs_expr: concat or verdict
and special case the recursive set specifications, as they deserve.
Besides making it a lot easier to understand what is actually supported,
this will be used by the following patch to support timeouts and comments
for keys in a uniform way.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
src/parser_bison.y | 31 ++++++++++++++++++-------------
1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index cd4e096..c934533 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -470,8 +470,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%destructor { expr_free($$); } prefix_expr range_expr wildcard_expr
%type <expr> list_expr
%destructor { expr_free($$); } list_expr
-%type <expr> concat_expr map_lhs_expr
-%destructor { expr_free($$); } concat_expr map_lhs_expr
+%type <expr> concat_expr
+%destructor { expr_free($$); } concat_expr
%type <expr> map_expr
%destructor { expr_free($$); } map_expr
@@ -484,6 +484,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <expr> set_expr set_list_expr set_list_member_expr
%destructor { expr_free($$); } set_expr set_list_expr set_list_member_expr
+%type <expr> set_lhs_expr set_rhs_expr
+%destructor { expr_free($$); } set_lhs_expr set_rhs_expr
%type <expr> expr initializer_expr
%destructor { expr_free($$); } expr initializer_expr
@@ -1297,13 +1299,12 @@ verdict_map_list_expr : verdict_map_list_member_expr
| verdict_map_list_expr COMMA opt_newline
;
-verdict_map_list_member_expr: opt_newline map_lhs_expr COLON verdict_expr opt_newline
+verdict_map_list_member_expr: opt_newline set_lhs_expr COLON verdict_expr opt_newline
{
$$ = mapping_expr_alloc(&@$, $2, $4);
}
;
-
counter_stmt : counter_stmt_alloc
| counter_stmt_alloc counter_args
@@ -1718,10 +1719,6 @@ multiton_expr : prefix_expr
| wildcard_expr
;
-map_lhs_expr : multiton_expr
- | concat_expr
- ;
-
map_expr : concat_expr MAP expr
{
$$ = map_expr_alloc(&@$, $1, $3);
@@ -1729,9 +1726,9 @@ map_expr : concat_expr MAP expr
;
expr : concat_expr
+ | multiton_expr
| set_expr
| map_expr
- | multiton_expr
;
set_expr : '{' set_list_expr '}'
@@ -1754,20 +1751,28 @@ set_list_expr : set_list_member_expr
| set_list_expr COMMA opt_newline
;
-set_list_member_expr : opt_newline expr opt_newline
+set_list_member_expr : opt_newline set_expr opt_newline
{
$$ = $2;
}
- | opt_newline map_lhs_expr COLON concat_expr opt_newline
+ | opt_newline set_lhs_expr opt_newline
{
- $$ = mapping_expr_alloc(&@$, $2, $4);
+ $$ = $2;
}
- | opt_newline map_lhs_expr COLON verdict_expr opt_newline
+ | opt_newline set_lhs_expr COLON set_rhs_expr opt_newline
{
$$ = mapping_expr_alloc(&@$, $2, $4);
}
;
+set_lhs_expr : concat_expr
+ | multiton_expr
+ ;
+
+set_rhs_expr : concat_expr
+ | verdict_expr
+ ;
+
initializer_expr : expr
| list_expr
;
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 06/10] expr: add set_elem_expr as container for set element attributes
2015-04-12 12:16 [PATCH 00/10] nftables: set timeouts and dynamic updates Patrick McHardy
` (4 preceding siblings ...)
2015-04-12 12:16 ` [PATCH 05/10] parser: fix inconsistencies in set expression rules Patrick McHardy
@ 2015-04-12 12:16 ` Patrick McHardy
2015-04-12 12:16 ` [PATCH 07/10] set: add timeout support for sets Patrick McHardy
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2015-04-12 12:16 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Add a new expression type "set_elem_expr" that is used as container for
the key in order to attach different attributes, such as timeout values,
to the key.
The expression hierarchy is as follows:
Sets:
elem
|
key
Maps:
mapping
/ \
elem data
|
key
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
include/expression.h | 8 +++++++
src/evaluate.c | 15 ++++++++++++++
src/expression.c | 31 +++++++++++++++++++++++++++
src/netlink.c | 53 +++++++++++++++++++++++++++--------------------
src/netlink_delinearize.c | 3 +++
src/netlink_linearize.c | 2 ++
src/parser_bison.y | 19 ++++++++++++-----
src/segtree.c | 8 +++++--
8 files changed, 109 insertions(+), 30 deletions(-)
diff --git a/include/expression.h b/include/expression.h
index 7477c3e..d481f28 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -27,6 +27,7 @@
* @EXPR_LIST: list of expressions
* @EXPR_SET: literal set
* @EXPR_SET_REF: set reference
+ * @EXPR_SET_ELEM: set element
* @EXPR_MAPPING: a single mapping (key : value)
* @EXPR_MAP: map operation (expr map { EXPR_MAPPING, ... })
* @EXPR_UNARY: byteorder conversion, generated during evaluation
@@ -48,6 +49,7 @@ enum expr_types {
EXPR_LIST,
EXPR_SET,
EXPR_SET_REF,
+ EXPR_SET_ELEM,
EXPR_MAPPING,
EXPR_MAP,
EXPR_UNARY,
@@ -230,6 +232,10 @@ struct expr {
struct set *set;
};
struct {
+ /* EXPR_SET_ELEM */
+ struct expr *key;
+ };
+ struct {
/* EXPR_UNARY */
struct expr *arg;
};
@@ -363,6 +369,8 @@ extern struct expr *map_expr_alloc(const struct location *loc,
extern struct expr *set_ref_expr_alloc(const struct location *loc,
struct set *set);
+extern struct expr *set_elem_expr_alloc(const struct location *loc,
+ struct expr *key);
extern void range_expr_value_low(mpz_t rop, const struct expr *expr);
extern void range_expr_value_high(mpz_t rop, const struct expr *expr);
diff --git a/src/evaluate.c b/src/evaluate.c
index 7ecb793..37db107 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -675,6 +675,19 @@ static int expr_evaluate_list(struct eval_ctx *ctx, struct expr **expr)
return 0;
}
+static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *elem = *expr;
+
+ if (expr_evaluate(ctx, &elem->key) < 0)
+ return -1;
+
+ elem->dtype = elem->key->dtype;
+ elem->len = elem->key->len;
+ elem->flags = elem->key->flags;
+ return 0;
+}
+
static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *set = *expr, *i, *next;
@@ -1100,6 +1113,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
return expr_evaluate_list(ctx, expr);
case EXPR_SET:
return expr_evaluate_set(ctx, expr);
+ case EXPR_SET_ELEM:
+ return expr_evaluate_set_elem(ctx, expr);
case EXPR_MAP:
return expr_evaluate_map(ctx, expr);
case EXPR_MAPPING:
diff --git a/src/expression.c b/src/expression.c
index 5b848da..6789396 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -886,6 +886,33 @@ struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set)
return expr;
}
+static void set_elem_expr_print(const struct expr *expr)
+{
+ expr_print(expr->key);
+}
+
+static void set_elem_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->key);
+}
+
+static const struct expr_ops set_elem_expr_ops = {
+ .type = EXPR_SET_ELEM,
+ .name = "set element",
+ .print = set_elem_expr_print,
+ .destroy = set_elem_expr_destroy,
+};
+
+struct expr *set_elem_expr_alloc(const struct location *loc, struct expr *key)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, &set_elem_expr_ops, key->dtype,
+ key->byteorder, key->len);
+ expr->key = key;
+ return expr;
+}
+
void range_expr_value_low(mpz_t rop, const struct expr *expr)
{
switch (expr->ops->type) {
@@ -897,6 +924,8 @@ void range_expr_value_low(mpz_t rop, const struct expr *expr)
return range_expr_value_low(rop, expr->left);
case EXPR_MAPPING:
return range_expr_value_low(rop, expr->left);
+ case EXPR_SET_ELEM:
+ return range_expr_value_low(rop, expr->key);
default:
BUG("invalid range expression type %s\n", expr->ops->name);
}
@@ -919,6 +948,8 @@ void range_expr_value_high(mpz_t rop, const struct expr *expr)
return range_expr_value_high(rop, expr->right);
case EXPR_MAPPING:
return range_expr_value_high(rop, expr->left);
+ case EXPR_SET_ELEM:
+ return range_expr_value_high(rop, expr->key);
default:
BUG("invalid range expression type %s\n", expr->ops->name);
}
diff --git a/src/netlink.c b/src/netlink.c
index f6fd065..75fbb25 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -205,6 +205,7 @@ struct nft_set *alloc_nft_set(const struct handle *h)
static struct nft_set_elem *alloc_nft_setelem(const struct expr *expr)
{
+ const struct expr *elem, *key, *data;
struct nft_set_elem *nlse;
struct nft_data_linearize nld;
@@ -212,24 +213,28 @@ static struct nft_set_elem *alloc_nft_setelem(const struct expr *expr)
if (nlse == NULL)
memory_allocation_error();
- if (expr->ops->type == EXPR_VALUE ||
- expr->flags & EXPR_F_INTERVAL_END) {
- netlink_gen_data(expr, &nld);
- nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_KEY,
- &nld.value, nld.len);
+ data = NULL;
+ if (expr->ops->type == EXPR_MAPPING) {
+ elem = expr->left;
+ if (!(expr->flags & EXPR_F_INTERVAL_END))
+ data = expr->right;
} else {
- assert(expr->ops->type == EXPR_MAPPING);
- netlink_gen_data(expr->left, &nld);
- nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_KEY,
- &nld.value, nld.len);
- netlink_gen_data(expr->right, &nld);
- switch (expr->right->ops->type) {
+ elem = expr;
+ }
+ key = elem->key;
+
+ netlink_gen_data(key, &nld);
+ nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_KEY, &nld.value, nld.len);
+
+ if (data != NULL) {
+ netlink_gen_data(data, &nld);
+ switch (data->ops->type) {
case EXPR_VERDICT:
nft_set_elem_attr_set_u32(nlse, NFT_SET_ELEM_ATTR_VERDICT,
- expr->right->verdict);
- if (expr->chain != NULL)
+ data->verdict);
+ if (data->chain != NULL)
nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_CHAIN,
- nld.chain, strlen(nld.chain));
+ nld.chain, strlen(nld.chain));
break;
case EXPR_VALUE:
nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_DATA,
@@ -1089,7 +1094,7 @@ static int netlink_delinearize_setelem(struct nft_set_elem *nlse,
struct set *set)
{
struct nft_data_delinearize nld;
- struct expr *expr, *data;
+ struct expr *expr, *key, *data;
uint32_t flags = 0;
nld.value =
@@ -1097,17 +1102,19 @@ static int netlink_delinearize_setelem(struct nft_set_elem *nlse,
if (nft_set_elem_attr_is_set(nlse, NFT_SET_ELEM_ATTR_FLAGS))
flags = nft_set_elem_attr_get_u32(nlse, NFT_SET_ELEM_ATTR_FLAGS);
- expr = netlink_alloc_value(&netlink_location, &nld);
- expr->dtype = set->keytype;
- expr->byteorder = set->keytype->byteorder;
+ key = netlink_alloc_value(&netlink_location, &nld);
+ key->dtype = set->keytype;
+ key->byteorder = set->keytype->byteorder;
if (!(set->flags & SET_F_INTERVAL) &&
- expr->byteorder == BYTEORDER_HOST_ENDIAN)
- mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+ key->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(key->value, key->len / BITS_PER_BYTE);
+
+ if (key->dtype->basetype != NULL &&
+ key->dtype->basetype->type == TYPE_BITMASK)
+ key = bitmask_expr_to_binops(key);
- if (expr->dtype->basetype != NULL &&
- expr->dtype->basetype->type == TYPE_BITMASK)
- expr = bitmask_expr_to_binops(expr);
+ expr = set_elem_expr_alloc(&netlink_location, key);
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 ec1a964..c564a8a 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1033,6 +1033,9 @@ static void expr_postprocess(struct rule_pp_ctx *ctx,
expr_postprocess(ctx, stmt, &expr->left);
expr_postprocess(ctx, stmt, &expr->right);
break;
+ case EXPR_SET_ELEM:
+ expr_postprocess(ctx, stmt, &expr->key);
+ break;
case EXPR_SET_REF:
case EXPR_EXTHDR:
case EXPR_META:
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 9bef67b..d1414c1 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -528,6 +528,8 @@ static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
return netlink_gen_meta(ctx, expr, dreg);
case EXPR_CT:
return netlink_gen_ct(ctx, expr, dreg);
+ case EXPR_SET_ELEM:
+ return netlink_gen_expr(ctx, expr->key, dreg);
default:
BUG("unknown expression type %s\n", expr->ops->name);
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index c934533..9fbc590 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -484,8 +484,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <expr> set_expr set_list_expr set_list_member_expr
%destructor { expr_free($$); } set_expr set_list_expr set_list_member_expr
-%type <expr> set_lhs_expr set_rhs_expr
-%destructor { expr_free($$); } set_lhs_expr set_rhs_expr
+%type <expr> set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr
+%destructor { expr_free($$); } set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr
%type <expr> expr initializer_expr
%destructor { expr_free($$); } expr initializer_expr
@@ -1299,7 +1299,7 @@ verdict_map_list_expr : verdict_map_list_member_expr
| verdict_map_list_expr COMMA opt_newline
;
-verdict_map_list_member_expr: opt_newline set_lhs_expr COLON verdict_expr opt_newline
+verdict_map_list_member_expr: opt_newline set_elem_expr COLON verdict_expr opt_newline
{
$$ = mapping_expr_alloc(&@$, $2, $4);
}
@@ -1755,16 +1755,25 @@ set_list_member_expr : opt_newline set_expr opt_newline
{
$$ = $2;
}
- | opt_newline set_lhs_expr opt_newline
+ | opt_newline set_elem_expr opt_newline
{
$$ = $2;
}
- | opt_newline set_lhs_expr COLON set_rhs_expr opt_newline
+ | opt_newline set_elem_expr COLON set_rhs_expr opt_newline
{
$$ = mapping_expr_alloc(&@$, $2, $4);
}
;
+set_elem_expr : set_elem_expr_alloc
+ ;
+
+set_elem_expr_alloc : set_lhs_expr
+ {
+ $$ = set_elem_expr_alloc(&@1, $1);
+ }
+ ;
+
set_lhs_expr : concat_expr
| multiton_expr
;
diff --git a/src/segtree.c b/src/segtree.c
index 65221e9..060951c 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -419,6 +419,7 @@ static void set_insert_interval(struct expr *set, struct seg_tree *tree,
expr = constant_expr_alloc(&internal_location, tree->keytype,
tree->byteorder, tree->keylen, NULL);
mpz_set(expr->value, ei->left);
+ expr = set_elem_expr_alloc(&internal_location, expr);
if (ei->expr != NULL && ei->expr->ops->type == EXPR_MAPPING)
expr = mapping_expr_alloc(&ei->expr->location, expr,
@@ -473,9 +474,9 @@ extern void interval_map_decompose(struct expr *set);
static struct expr *expr_value(struct expr *expr)
{
if (expr->ops->type == EXPR_MAPPING)
- return expr->left;
+ return expr->left->key;
else
- return expr;
+ return expr->key;
}
static int expr_value_cmp(const void *p1, const void *p2)
@@ -565,6 +566,7 @@ void interval_map_decompose(struct expr *set)
mpz_set(tmp->value, range);
tmp = range_expr_alloc(&low->location, expr_value(low), tmp);
+ tmp = set_elem_expr_alloc(&low->location, tmp);
if (low->ops->type == EXPR_MAPPING)
tmp = mapping_expr_alloc(&tmp->location, tmp, low->right);
@@ -576,6 +578,7 @@ void interval_map_decompose(struct expr *set)
prefix_len = expr_value(i)->len - mpz_scan0(range, 0);
prefix = prefix_expr_alloc(&low->location, expr_value(low),
prefix_len);
+ prefix = set_elem_expr_alloc(&low->location, prefix);
if (low->ops->type == EXPR_MAPPING)
prefix = mapping_expr_alloc(&low->location, prefix,
low->right);
@@ -598,6 +601,7 @@ void interval_map_decompose(struct expr *set)
mpz_init_bitmask(i->value, i->len);
i = range_expr_alloc(&low->location, expr_value(low), i);
+ i = set_elem_expr_alloc(&low->location, i);
if (low->ops->type == EXPR_MAPPING)
i = mapping_expr_alloc(&i->location, i, low->right);
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 07/10] set: add timeout support for sets
2015-04-12 12:16 [PATCH 00/10] nftables: set timeouts and dynamic updates Patrick McHardy
` (5 preceding siblings ...)
2015-04-12 12:16 ` [PATCH 06/10] expr: add set_elem_expr as container for set element attributes Patrick McHardy
@ 2015-04-12 12:16 ` Patrick McHardy
2015-04-12 12:16 ` [PATCH 08/10] setelem: add timeout support for set elements Patrick McHardy
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2015-04-12 12:16 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Timeout support can be enabled in one of two ways:
1. Using a default timeout value:
set test {
type ipv4_addr;
timeout 1h;
}
2. Using the timeout flag without a default:
set test {
type ipv4_addr;
flags timeout;
}
Optionally a garbage collection interval can be specified using
gc-interval <interval>;
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
include/linux/netfilter/nf_tables.h | 6 ++++++
include/rule.h | 5 +++++
src/evaluate.c | 4 ++++
src/netlink.c | 10 ++++++++++
src/parser_bison.y | 13 +++++++++++++
src/rule.c | 23 ++++++++++++++++++++++-
src/scanner.l | 2 ++
7 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 832bc46..8671505 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -207,12 +207,14 @@ enum nft_rule_compat_attributes {
* @NFT_SET_CONSTANT: set contents may not change while bound
* @NFT_SET_INTERVAL: set contains intervals
* @NFT_SET_MAP: set is used as a dictionary
+ * @NFT_SET_TIMEOUT: set uses timeouts
*/
enum nft_set_flags {
NFT_SET_ANONYMOUS = 0x1,
NFT_SET_CONSTANT = 0x2,
NFT_SET_INTERVAL = 0x4,
NFT_SET_MAP = 0x8,
+ NFT_SET_TIMEOUT = 0x10,
};
/**
@@ -251,6 +253,8 @@ enum nft_set_desc_attributes {
* @NFTA_SET_POLICY: selection policy (NLA_U32)
* @NFTA_SET_DESC: set description (NLA_NESTED)
* @NFTA_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
+ * @NFTA_SET_TIMEOUT: default timeout value (NLA_U64)
+ * @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
*/
enum nft_set_attributes {
NFTA_SET_UNSPEC,
@@ -264,6 +268,8 @@ enum nft_set_attributes {
NFTA_SET_POLICY,
NFTA_SET_DESC,
NFTA_SET_ID,
+ NFTA_SET_TIMEOUT,
+ NFTA_SET_GC_INTERVAL,
__NFTA_SET_MAX
};
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
diff --git a/include/rule.h b/include/rule.h
index 97959f7..5d44599 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -173,6 +173,7 @@ enum set_flags {
SET_F_CONSTANT = 0x2,
SET_F_INTERVAL = 0x4,
SET_F_MAP = 0x8,
+ SET_F_TIMEOUT = 0x10,
};
/**
@@ -183,6 +184,8 @@ enum set_flags {
* @location: location the set was defined/declared at
* @refcnt: reference count
* @flags: bitmask of set flags
+ * @gc_int: garbage collection interval
+ * @timeout: default timeout value
* @keytype: key data type
* @keylen: key length
* @datatype: mapping data type
@@ -197,6 +200,8 @@ struct set {
struct location location;
unsigned int refcnt;
uint32_t flags;
+ uint32_t gc_int;
+ uint64_t timeout;
const struct datatype *keytype;
unsigned int keylen;
const struct datatype *datatype;
diff --git a/src/evaluate.c b/src/evaluate.c
index 37db107..04ca08d 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1737,6 +1737,10 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
return -1;
}
+ /* Default timeout value implies timeout support */
+ if (set->timeout)
+ set->flags |= SET_F_TIMEOUT;
+
if (!(set->flags & SET_F_MAP))
return 0;
diff --git a/src/netlink.c b/src/netlink.c
index 75fbb25..337d8a1 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -908,6 +908,11 @@ static struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
set->datalen = data_len * BITS_PER_BYTE;
}
+ if (nft_set_attr_is_set(nls, NFT_SET_ATTR_TIMEOUT))
+ set->timeout = nft_set_attr_get_u64(nls, NFT_SET_ATTR_TIMEOUT);
+ if (nft_set_attr_is_set(nls, NFT_SET_ATTR_GC_INTERVAL))
+ set->gc_int = nft_set_attr_get_u32(nls, NFT_SET_ATTR_GC_INTERVAL);
+
if (nft_set_attr_is_set(nls, NFT_SET_ATTR_POLICY))
set->policy = nft_set_attr_get_u32(nls, NFT_SET_ATTR_POLICY);
@@ -939,6 +944,11 @@ int netlink_add_set(struct netlink_ctx *ctx, const struct handle *h,
nft_set_attr_set_u32(nls, NFT_SET_ATTR_DATA_LEN,
set->datalen / BITS_PER_BYTE);
}
+ if (set->timeout)
+ nft_set_attr_set_u64(nls, NFT_SET_ATTR_TIMEOUT, set->timeout);
+ if (set->gc_int)
+ nft_set_attr_set_u32(nls, NFT_SET_ATTR_GC_INTERVAL, set->gc_int);
+
set->handle.set_id = ++set_id;
nft_set_attr_set_u32(nls, NFT_SET_ATTR_ID, set->handle.set_id);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 9fbc590..8083187 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -201,6 +201,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token CONSTANT "constant"
%token INTERVAL "interval"
+%token TIMEOUT "timeout"
+%token GC_INTERVAL "gc-interval"
%token ELEMENTS "elements"
%token POLICY "policy"
@@ -944,6 +946,16 @@ set_block : /* empty */ { $$ = $<set>-1; }
$1->flags = $3;
$$ = $1;
}
+ | set_block TIMEOUT time_spec stmt_seperator
+ {
+ $1->timeout = $3 * 1000;
+ $$ = $1;
+ }
+ | set_block GC_INTERVAL time_spec stmt_seperator
+ {
+ $1->gc_int = $3 * 1000;
+ $$ = $1;
+ }
| set_block ELEMENTS '=' set_expr
{
$1->init = $4;
@@ -961,6 +973,7 @@ set_flag_list : set_flag_list COMMA set_flag
set_flag : CONSTANT { $$ = SET_F_CONSTANT; }
| INTERVAL { $$ = SET_F_INTERVAL; }
+ | TIMEOUT { $$ = SET_F_TIMEOUT; }
;
map_block_alloc : /* empty */
diff --git a/src/rule.c b/src/rule.c
index 86cf080..a9ed749 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -136,6 +136,7 @@ static void do_set_print(const struct set *set, struct print_fmt_options *opts)
{
const char *delim = "";
const char *type;
+ uint32_t flags;
type = set->flags & SET_F_MAP ? "map" : "set";
printf("%s%s", opts->tab, type);
@@ -167,7 +168,12 @@ static void do_set_print(const struct set *set, struct print_fmt_options *opts)
}
}
- if (set->flags & (SET_F_CONSTANT | SET_F_INTERVAL)) {
+ flags = set->flags;
+ /* "timeout" flag is redundant if a default timeout exists */
+ if (set->timeout)
+ flags &= ~SET_F_TIMEOUT;
+
+ if (flags & (SET_F_CONSTANT | SET_F_INTERVAL | SET_F_TIMEOUT)) {
printf("%s%sflags ", opts->tab, opts->tab);
if (set->flags & SET_F_CONSTANT) {
printf("%sconstant", delim);
@@ -177,6 +183,21 @@ static void do_set_print(const struct set *set, struct print_fmt_options *opts)
printf("%sinterval", delim);
delim = ",";
}
+ if (set->flags & SET_F_TIMEOUT) {
+ printf("%stimeout", delim);
+ delim = ",";
+ }
+ printf("%s", opts->nl);
+ }
+
+ if (set->timeout) {
+ printf("%s%stimeout ", opts->tab, opts->tab);
+ time_print(set->timeout / 1000);
+ printf("%s", opts->nl);
+ }
+ if (set->gc_int) {
+ printf("%s%sgc-interval ", opts->tab, opts->tab);
+ time_print(set->gc_int / 1000);
printf("%s", opts->nl);
}
diff --git a/src/scanner.l b/src/scanner.l
index 27d95bf..4231d27 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -271,6 +271,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"constant" { return CONSTANT; }
"interval" { return INTERVAL; }
+"timeout" { return TIMEOUT; }
+"gc-interval" { return GC_INTERVAL; }
"elements" { return ELEMENTS; }
"policy" { return POLICY; }
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 08/10] setelem: add timeout support for set elements
2015-04-12 12:16 [PATCH 00/10] nftables: set timeouts and dynamic updates Patrick McHardy
` (6 preceding siblings ...)
2015-04-12 12:16 ` [PATCH 07/10] set: add timeout support for sets Patrick McHardy
@ 2015-04-12 12:16 ` Patrick McHardy
2015-04-12 12:16 ` [PATCH 09/10] setelem: add support for attaching comments to " Patrick McHardy
2015-04-12 12:16 ` [PATCH 10/10] nftables: add set statement Patrick McHardy
9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2015-04-12 12:16 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Support specifying per element timeout values and displaying the expiration
time.
If an element should not use the default timeout value of the set, an
element specific value can be specified as follows:
# nft add element filter test { 192.168.0.1, 192.168.0.2 timeout 10m}
For listing of elements that use the default timeout value, just the
expiration time is shown, otherwise the element specific timeout value
is also displayed:
set test {
type ipv4_addr
timeout 1h
elements = { 192.168.0.2 timeout 10m expires 9m59s, 192.168.0.1 expires 59m59s}
}
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
include/expression.h | 2 ++
include/linux/netfilter/nf_tables.h | 4 ++++
src/expression.c | 8 ++++++++
src/netlink.c | 7 +++++++
src/parser_bison.y | 14 ++++++++++++++
5 files changed, 35 insertions(+)
diff --git a/include/expression.h b/include/expression.h
index d481f28..6f23b6d 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -234,6 +234,8 @@ struct expr {
struct {
/* EXPR_SET_ELEM */
struct expr *key;
+ uint64_t timeout;
+ uint64_t expiration;
};
struct {
/* EXPR_UNARY */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 8671505..6894ba3 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -289,12 +289,16 @@ enum nft_set_elem_flags {
* @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data)
* @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes)
* @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
+ * @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64)
+ * @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
*/
enum nft_set_elem_attributes {
NFTA_SET_ELEM_UNSPEC,
NFTA_SET_ELEM_KEY,
NFTA_SET_ELEM_DATA,
NFTA_SET_ELEM_FLAGS,
+ NFTA_SET_ELEM_TIMEOUT,
+ NFTA_SET_ELEM_EXPIRATION,
__NFTA_SET_ELEM_MAX
};
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
diff --git a/src/expression.c b/src/expression.c
index 6789396..2037c60 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -889,6 +889,14 @@ struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set)
static void set_elem_expr_print(const struct expr *expr)
{
expr_print(expr->key);
+ if (expr->timeout) {
+ printf(" timeout ");
+ time_print(expr->timeout / 1000);
+ }
+ if (expr->expiration) {
+ printf(" expires ");
+ time_print(expr->expiration / 1000);
+ }
}
static void set_elem_expr_destroy(struct expr *expr)
diff --git a/src/netlink.c b/src/netlink.c
index 337d8a1..4de4f47 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -225,6 +225,9 @@ static struct nft_set_elem *alloc_nft_setelem(const struct expr *expr)
netlink_gen_data(key, &nld);
nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_KEY, &nld.value, nld.len);
+ if (elem->timeout)
+ nft_set_elem_attr_set_u64(nlse, NFT_SET_ELEM_ATTR_TIMEOUT,
+ elem->timeout);
if (data != NULL) {
netlink_gen_data(data, &nld);
@@ -1125,6 +1128,10 @@ static int netlink_delinearize_setelem(struct nft_set_elem *nlse,
key = bitmask_expr_to_binops(key);
expr = set_elem_expr_alloc(&netlink_location, key);
+ if (nft_set_elem_attr_is_set(nlse, NFT_SET_ELEM_ATTR_TIMEOUT))
+ expr->timeout = nft_set_elem_attr_get_u64(nlse, NFT_SET_ELEM_ATTR_TIMEOUT);
+ if (nft_set_elem_attr_is_set(nlse, NFT_SET_ELEM_ATTR_EXPIRATION))
+ expr->expiration = nft_set_elem_attr_get_u64(nlse, NFT_SET_ELEM_ATTR_EXPIRATION);
if (flags & NFT_SET_ELEM_INTERVAL_END) {
expr->flags |= EXPR_F_INTERVAL_END;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 8083187..736704a 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -1779,6 +1779,7 @@ set_list_member_expr : opt_newline set_expr opt_newline
;
set_elem_expr : set_elem_expr_alloc
+ | set_elem_expr_alloc set_elem_options
;
set_elem_expr_alloc : set_lhs_expr
@@ -1787,6 +1788,19 @@ set_elem_expr_alloc : set_lhs_expr
}
;
+set_elem_options : set_elem_option
+ {
+ $<expr>$ = $<expr>0;
+ }
+ | set_elem_options set_elem_option
+ ;
+
+set_elem_option : TIMEOUT time_spec
+ {
+ $<expr>0->timeout = $2 * 1000;
+ }
+ ;
+
set_lhs_expr : concat_expr
| multiton_expr
;
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 09/10] setelem: add support for attaching comments to set elements
2015-04-12 12:16 [PATCH 00/10] nftables: set timeouts and dynamic updates Patrick McHardy
` (7 preceding siblings ...)
2015-04-12 12:16 ` [PATCH 08/10] setelem: add timeout support for set elements Patrick McHardy
@ 2015-04-12 12:16 ` Patrick McHardy
2015-04-12 12:16 ` [PATCH 10/10] nftables: add set statement Patrick McHardy
9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2015-04-12 12:16 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Syntax:
# nft add element filter test { 192.168.0.1 comment "some host" }
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
include/expression.h | 1 +
include/linux/netfilter/nf_tables.h | 2 ++
src/expression.c | 3 +++
src/netlink.c | 11 +++++++++++
src/parser_bison.y | 4 ++++
5 files changed, 21 insertions(+)
diff --git a/include/expression.h b/include/expression.h
index 6f23b6d..010cb95 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -236,6 +236,7 @@ struct expr {
struct expr *key;
uint64_t timeout;
uint64_t expiration;
+ const char *comment;
};
struct {
/* EXPR_UNARY */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 6894ba3..334b389 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -291,6 +291,7 @@ enum nft_set_elem_flags {
* @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
* @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64)
* @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
+ * @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
*/
enum nft_set_elem_attributes {
NFTA_SET_ELEM_UNSPEC,
@@ -299,6 +300,7 @@ enum nft_set_elem_attributes {
NFTA_SET_ELEM_FLAGS,
NFTA_SET_ELEM_TIMEOUT,
NFTA_SET_ELEM_EXPIRATION,
+ NFTA_SET_ELEM_USERDATA,
__NFTA_SET_ELEM_MAX
};
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
diff --git a/src/expression.c b/src/expression.c
index 2037c60..3edc550 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -897,10 +897,13 @@ static void set_elem_expr_print(const struct expr *expr)
printf(" expires ");
time_print(expr->expiration / 1000);
}
+ if (expr->comment)
+ printf(" comment \"%s\"", expr->comment);
}
static void set_elem_expr_destroy(struct expr *expr)
{
+ xfree(expr->comment);
expr_free(expr->key);
}
diff --git a/src/netlink.c b/src/netlink.c
index 4de4f47..23403bd 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -228,6 +228,9 @@ static struct nft_set_elem *alloc_nft_setelem(const struct expr *expr)
if (elem->timeout)
nft_set_elem_attr_set_u64(nlse, NFT_SET_ELEM_ATTR_TIMEOUT,
elem->timeout);
+ if (elem->comment)
+ nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_USERDATA,
+ elem->comment, strlen(elem->comment) + 1);
if (data != NULL) {
netlink_gen_data(data, &nld);
@@ -1132,6 +1135,14 @@ static int netlink_delinearize_setelem(struct nft_set_elem *nlse,
expr->timeout = nft_set_elem_attr_get_u64(nlse, NFT_SET_ELEM_ATTR_TIMEOUT);
if (nft_set_elem_attr_is_set(nlse, NFT_SET_ELEM_ATTR_EXPIRATION))
expr->expiration = nft_set_elem_attr_get_u64(nlse, NFT_SET_ELEM_ATTR_EXPIRATION);
+ if (nft_set_elem_attr_is_set(nlse, NFT_SET_ELEM_ATTR_USERDATA)) {
+ const void *data;
+ uint32_t len;
+
+ data = nft_set_elem_attr_get(nlse, NFT_SET_ELEM_ATTR_USERDATA, &len);
+ expr->comment = xmalloc(len);
+ memcpy((char *)expr->comment, data, len);
+ }
if (flags & NFT_SET_ELEM_INTERVAL_END) {
expr->flags |= EXPR_F_INTERVAL_END;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 736704a..0f2d71a 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -1799,6 +1799,10 @@ set_elem_option : TIMEOUT time_spec
{
$<expr>0->timeout = $2 * 1000;
}
+ | COMMENT string
+ {
+ $<expr>0->comment = $2;
+ }
;
set_lhs_expr : concat_expr
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 10/10] nftables: add set statement
2015-04-12 12:16 [PATCH 00/10] nftables: set timeouts and dynamic updates Patrick McHardy
` (8 preceding siblings ...)
2015-04-12 12:16 ` [PATCH 09/10] setelem: add support for attaching comments to " Patrick McHardy
@ 2015-04-12 12:16 ` Patrick McHardy
9 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2015-04-12 12:16 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
The set statement is used to dynamically add or update elements in a set.
Syntax:
# nft filter input set add tcp dport @myset
# nft filter input set add ip saddr timeout 10s @myset
# nft filter input set update ip saddr timeout 10s @myset
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
include/linux/netfilter/nf_tables.h | 27 ++++++++++++++++++++++++++
include/statement.h | 11 +++++++++++
src/evaluate.c | 28 ++++++++++++++++++++++++++-
src/netlink_delinearize.c | 38 +++++++++++++++++++++++++++++++++++++
src/netlink_linearize.c | 24 +++++++++++++++++++++++
src/parser_bison.y | 18 ++++++++++++++++++
src/scanner.l | 1 +
src/statement.c | 31 ++++++++++++++++++++++++++++++
8 files changed, 177 insertions(+), 1 deletion(-)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 334b389..0e96443 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -516,6 +516,33 @@ enum nft_lookup_attributes {
};
#define NFTA_LOOKUP_MAX (__NFTA_LOOKUP_MAX - 1)
+enum nft_dynset_ops {
+ NFT_DYNSET_OP_ADD,
+ NFT_DYNSET_OP_UPDATE,
+};
+
+/**
+ * enum nft_dynset_attributes - dynset expression attributes
+ *
+ * @NFTA_DYNSET_SET_NAME: name of set the to add data to (NLA_STRING)
+ * @NFTA_DYNSET_SET_ID: uniquely identifier of the set in the transaction (NLA_U32)
+ * @NFTA_DYNSET_OP: operation (NLA_U32)
+ * @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)
+ */
+enum nft_dynset_attributes {
+ NFTA_DYNSET_UNSPEC,
+ NFTA_DYNSET_SET_NAME,
+ NFTA_DYNSET_SET_ID,
+ NFTA_DYNSET_OP,
+ NFTA_DYNSET_SREG_KEY,
+ NFTA_DYNSET_SREG_DATA,
+ NFTA_DYNSET_TIMEOUT,
+ __NFTA_DYNSET_MAX,
+};
+#define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1)
+
/**
* enum nft_payload_bases - nf_tables payload expression offset bases
*
diff --git a/include/statement.h b/include/statement.h
index d143121..48e6130 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -104,6 +104,14 @@ extern struct stmt *ct_stmt_alloc(const struct location *loc,
enum nft_ct_keys key,
struct expr *expr);
+struct set_stmt {
+ struct expr *set;
+ struct expr *key;
+ enum nft_dynset_ops op;
+};
+
+extern struct stmt *set_stmt_alloc(const struct location *loc);
+
/**
* enum stmt_types - statement types
*
@@ -120,6 +128,7 @@ extern struct stmt *ct_stmt_alloc(const struct location *loc,
* @STMT_REDIR: redirect statement
* @STMT_QUEUE: QUEUE statement
* @STMT_CT: conntrack statement
+ * @STMT_SET: set statement
*/
enum stmt_types {
STMT_INVALID,
@@ -135,6 +144,7 @@ enum stmt_types {
STMT_REDIR,
STMT_QUEUE,
STMT_CT,
+ STMT_SET,
};
/**
@@ -184,6 +194,7 @@ struct stmt {
struct redir_stmt redir;
struct queue_stmt queue;
struct ct_stmt ct;
+ struct set_stmt set;
};
};
diff --git a/src/evaluate.c b/src/evaluate.c
index 04ca08d..e260a80 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -614,7 +614,7 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
struct expr *i, *next;
list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
- if (dtype && off == 0)
+ if (expr_is_constant(*expr) && dtype && off == 0)
return expr_binary_error(ctx->msgs, i, *expr,
"unexpected concat component, "
"expecting %s",
@@ -1661,6 +1661,30 @@ static int stmt_evaluate_log(struct eval_ctx *ctx, struct stmt *stmt)
return 0;
}
+static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ expr_set_context(&ctx->ectx, NULL, 0);
+ if (expr_evaluate(ctx, &stmt->set.set) < 0)
+ return -1;
+ if (stmt->set.set->ops->type != EXPR_SET_REF)
+ return expr_error(ctx->msgs, stmt->set.set,
+ "Expression does not refer to a set");
+
+ if (stmt_evaluate_arg(ctx, stmt,
+ stmt->set.set->set->keytype,
+ stmt->set.set->set->keylen,
+ &stmt->set.key) < 0)
+ return -1;
+ if (expr_is_constant(stmt->set.key))
+ return expr_error(ctx->msgs, stmt->set.key,
+ "Key expression can not be constant");
+ if (stmt->set.key->comment != NULL)
+ return expr_error(ctx->msgs, stmt->set.key,
+ "Key expression comments are not supported");
+
+ return 0;
+}
+
int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
{
#ifdef DEBUG
@@ -1695,6 +1719,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
return stmt_evaluate_redir(ctx, stmt);
case STMT_QUEUE:
return stmt_evaluate_queue(ctx, stmt);
+ case STMT_SET:
+ return stmt_evaluate_set(ctx, stmt);
default:
BUG("unknown statement type %s\n", stmt->ops->name);
}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index c564a8a..89d8522 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -694,6 +694,40 @@ static void netlink_parse_queue(struct netlink_parse_ctx *ctx,
list_add_tail(&stmt->list, &ctx->rule->stmts);
}
+static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nft_rule_expr *nle)
+{
+ struct expr *expr;
+ struct stmt *stmt;
+ struct set *set;
+ enum nft_registers sreg;
+ const char *name;
+
+ sreg = netlink_parse_register(nle, NFT_EXPR_DYNSET_SREG_KEY);
+ expr = netlink_get_register(ctx, loc, sreg);
+ if (expr == NULL)
+ return netlink_error(ctx, loc,
+ "Dynset statement has no key expression");
+
+ expr = set_elem_expr_alloc(&expr->location, expr);
+ expr->timeout = nft_rule_expr_get_u64(nle, NFT_EXPR_DYNSET_TIMEOUT);
+
+ name = nft_rule_expr_get_str(nle, NFT_EXPR_DYNSET_SET_NAME);
+ set = set_lookup(ctx->table, name);
+ if (set == NULL)
+ return netlink_error(ctx, loc,
+ "Unknown set '%s' in dynset statement",
+ name);
+
+ stmt = set_stmt_alloc(loc);
+ stmt->set.set = set_ref_expr_alloc(loc, set);
+ stmt->set.op = nft_rule_expr_get_u32(nle, NFT_EXPR_DYNSET_OP);
+ stmt->set.key = expr;
+
+ list_add_tail(&stmt->list, &ctx->rule->stmts);
+}
+
static const struct {
const char *name;
void (*parse)(struct netlink_parse_ctx *ctx,
@@ -717,6 +751,7 @@ static const struct {
{ .name = "masq", .parse = netlink_parse_masq },
{ .name = "redir", .parse = netlink_parse_redir },
{ .name = "queue", .parse = netlink_parse_queue },
+ { .name = "dynset", .parse = netlink_parse_dynset },
};
static int netlink_parse_expr(struct nft_rule_expr *nle, void *arg)
@@ -1140,6 +1175,9 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
case STMT_REJECT:
stmt_reject_postprocess(rctx, stmt);
break;
+ case STMT_SET:
+ expr_postprocess(&rctx, stmt, &stmt->set.key);
+ break;
default:
break;
}
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index d1414c1..09ba2ef 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -800,6 +800,28 @@ static void netlink_gen_ct_stmt(struct netlink_linearize_ctx *ctx,
nft_rule_add_expr(ctx->nlr, nle);
}
+static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nft_rule_expr *nle;
+ enum nft_registers sreg_key;
+
+ sreg_key = get_register(ctx);
+ netlink_gen_expr(ctx, stmt->set.key, sreg_key);
+ release_register(ctx);
+
+ nle = alloc_nft_expr("dynset");
+ netlink_put_register(nle, NFT_EXPR_DYNSET_SREG_KEY, sreg_key);
+ nft_rule_expr_set_u64(nle, NFT_EXPR_DYNSET_TIMEOUT,
+ stmt->set.key->timeout);
+ nft_rule_expr_set_u32(nle, NFT_EXPR_DYNSET_OP, stmt->set.op);
+ nft_rule_expr_set_str(nle, NFT_EXPR_DYNSET_SET_NAME,
+ stmt->set.set->set->handle.set);
+ nft_rule_expr_set_u32(nle, NFT_EXPR_DYNSET_SET_ID,
+ stmt->set.set->set->handle.set_id);
+ nft_rule_add_expr(ctx->nlr, nle);
+}
+
static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
@@ -828,6 +850,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
return netlink_gen_queue_stmt(ctx, stmt);
case STMT_CT:
return netlink_gen_ct_stmt(ctx, stmt);
+ case STMT_SET:
+ return netlink_gen_set_stmt(ctx, stmt);
default:
BUG("unknown statement type %s\n", stmt->ops->name);
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 0f2d71a..eac3fcb 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -181,6 +181,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token INET "inet"
%token ADD "add"
+%token UPDATE "update"
%token CREATE "create"
%token INSERT "insert"
%token DELETE "delete"
@@ -456,6 +457,9 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <stmt> queue_stmt queue_stmt_alloc
%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc
%type <val> queue_stmt_flags queue_stmt_flag
+%type <stmt> set_stmt
+%destructor { stmt_free($$); } set_stmt
+%type <val> set_stmt_op
%type <expr> symbol_expr verdict_expr integer_expr
%destructor { expr_free($$); } symbol_expr verdict_expr integer_expr
@@ -1267,6 +1271,7 @@ stmt : verdict_stmt
| ct_stmt
| masq_stmt
| redir_stmt
+ | set_stmt
;
verdict_stmt : verdict_expr
@@ -1579,6 +1584,19 @@ queue_stmt_flag : BYPASS { $$ = NFT_QUEUE_FLAG_BYPASS; }
| FANOUT { $$ = NFT_QUEUE_FLAG_CPU_FANOUT; }
;
+set_stmt : SET set_stmt_op set_elem_expr symbol_expr
+ {
+ $$ = set_stmt_alloc(&@$);
+ $$->set.op = $2;
+ $$->set.key = $3;
+ $$->set.set = $4;
+ }
+ ;
+
+set_stmt_op : ADD { $$ = NFT_DYNSET_OP_ADD; }
+ | UPDATE { $$ = NFT_DYNSET_OP_UPDATE; }
+ ;
+
match_stmt : relational_expr
{
$$ = expr_stmt_alloc(&@$, $1);
diff --git a/src/scanner.l b/src/scanner.l
index 4231d27..985ea2a 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -257,6 +257,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"inet" { return INET; }
"add" { return ADD; }
+"update" { return UPDATE; }
"create" { return CREATE; }
"insert" { return INSERT; }
"delete" { return DELETE; }
diff --git a/src/statement.c b/src/statement.c
index d72c6e9..9ebc593 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -377,3 +377,34 @@ struct stmt *redir_stmt_alloc(const struct location *loc)
{
return stmt_alloc(loc, &redir_stmt_ops);
}
+
+static const char * const set_stmt_op_names[] = {
+ [NFT_DYNSET_OP_ADD] = "add",
+ [NFT_DYNSET_OP_UPDATE] = "update",
+};
+
+static void set_stmt_print(const struct stmt *stmt)
+{
+ printf("set %s ", set_stmt_op_names[stmt->set.op]);
+ expr_print(stmt->set.key);
+ printf(" ");
+ expr_print(stmt->set.set);
+}
+
+static void set_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->set.key);
+ expr_free(stmt->set.set);
+}
+
+static const struct stmt_ops set_stmt_ops = {
+ .type = STMT_SET,
+ .name = "set",
+ .print = set_stmt_print,
+ .destroy = set_stmt_destroy,
+};
+
+struct stmt *set_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &set_stmt_ops);
+}
--
2.1.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2015-04-12 12:16 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-04-12 12:16 [PATCH 00/10] nftables: set timeouts and dynamic updates Patrick McHardy
2015-04-12 12:16 ` [PATCH 01/10] datatype: fix parsing of time type Patrick McHardy
2015-04-12 12:16 ` [PATCH 02/10] datatype: less strict time parsing Patrick McHardy
2015-04-12 12:16 ` [PATCH 03/10] datatype: seperate time parsing/printing from time_type Patrick McHardy
2015-04-12 12:16 ` [PATCH 04/10] parser: add a time_spec rule Patrick McHardy
2015-04-12 12:16 ` [PATCH 05/10] parser: fix inconsistencies in set expression rules Patrick McHardy
2015-04-12 12:16 ` [PATCH 06/10] expr: add set_elem_expr as container for set element attributes Patrick McHardy
2015-04-12 12:16 ` [PATCH 07/10] set: add timeout support for sets Patrick McHardy
2015-04-12 12:16 ` [PATCH 08/10] setelem: add timeout support for set elements Patrick McHardy
2015-04-12 12:16 ` [PATCH 09/10] setelem: add support for attaching comments to " Patrick McHardy
2015-04-12 12:16 ` [PATCH 10/10] nftables: add set statement Patrick McHardy
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).