summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2021-05-10 18:52:45 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2021-05-11 21:39:01 +0200
commit419d196886889e9b37f76f8c803cb08dcbc05505 (patch)
treeeed1e42837a4a55d8cf16e65914b9ae961adddcd /src
parent62b02808594d962f83e8b76f4da32da0673c7cfe (diff)
src: add set element catch-all support
Add a catchall expression (EXPR_SET_ELEM_CATCHALL). Use the asterisk (*) to represent the catch-all set element, e.g. table x { set y { type ipv4_addr counter elements = { 1.2.3.4 counter packets 0 bytes 0, * counter packets 0 bytes 0 } } } Special handling for segtree: zap the catch-all element from the set element list and re-add it after processing. Remove wildcard_expr deadcode in src/parser_bison.y This patch also adds several tests for the tests/py and tests/shell infrastructures. Acked-by: Phil Sutter <phil@nwl.cc> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/evaluate.c2
-rw-r--r--src/expression.c24
-rw-r--r--src/mergesort.c4
-rw-r--r--src/netlink.c71
-rw-r--r--src/parser_bison.y19
-rw-r--r--src/segtree.c41
6 files changed, 118 insertions, 43 deletions
diff --git a/src/evaluate.c b/src/evaluate.c
index b5dcdd35..95189180 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2201,6 +2201,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
return expr_evaluate_hash(ctx, expr);
case EXPR_XFRM:
return expr_evaluate_xfrm(ctx, expr);
+ case EXPR_SET_ELEM_CATCHALL:
+ return 0;
default:
BUG("unknown expression type %s\n", expr_name(*expr));
}
diff --git a/src/expression.c b/src/expression.c
index 9fdf23d9..b3400751 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1328,6 +1328,29 @@ struct expr *set_elem_expr_alloc(const struct location *loc, struct expr *key)
return expr;
}
+static void set_elem_catchall_expr_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ nft_print(octx, "*");
+}
+
+static const struct expr_ops set_elem_catchall_expr_ops = {
+ .type = EXPR_SET_ELEM_CATCHALL,
+ .name = "catch-all set element",
+ .print = set_elem_catchall_expr_print,
+};
+
+struct expr *set_elem_catchall_expr_alloc(const struct location *loc)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_SET_ELEM_CATCHALL, &invalid_type,
+ BYTEORDER_INVALID, 0);
+ expr->flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
+
+ return expr;
+}
+
void range_expr_value_low(mpz_t rop, const struct expr *expr)
{
switch (expr->etype) {
@@ -1403,6 +1426,7 @@ static const struct expr_ops *__expr_ops_by_type(enum expr_types etype)
case EXPR_RT: return &rt_expr_ops;
case EXPR_FIB: return &fib_expr_ops;
case EXPR_XFRM: return &xfrm_expr_ops;
+ case EXPR_SET_ELEM_CATCHALL: return &set_elem_catchall_expr_ops;
}
BUG("Unknown expression type %d\n", etype);
diff --git a/src/mergesort.c b/src/mergesort.c
index 41f35856..152b0556 100644
--- a/src/mergesort.c
+++ b/src/mergesort.c
@@ -44,6 +44,10 @@ static void expr_msort_value(const struct expr *expr, mpz_t value)
case EXPR_CONCAT:
concat_expr_msort_value(expr, value);
break;
+ case EXPR_SET_ELEM_CATCHALL:
+ /* max value to ensure listing shows it in the last position */
+ mpz_bitmask(value, expr->len);
+ break;
default:
BUG("Unknown expression %s\n", expr_name(expr));
}
diff --git a/src/netlink.c b/src/netlink.c
index e4926a80..8cdd6d81 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -104,6 +104,7 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
struct nftnl_set_elem *nlse;
struct nft_data_linearize nld;
struct nftnl_udata_buf *udbuf = NULL;
+ uint32_t flags = 0;
int num_exprs = 0;
struct stmt *stmt;
struct expr *key;
@@ -125,16 +126,21 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
key = elem->key;
- netlink_gen_data(key, &nld);
- nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len);
-
- if (set->set_flags & NFT_SET_INTERVAL && key->field_count > 1) {
- key->flags |= EXPR_F_INTERVAL_END;
+ switch (key->etype) {
+ case EXPR_SET_ELEM_CATCHALL:
+ break;
+ default:
netlink_gen_data(key, &nld);
- key->flags &= ~EXPR_F_INTERVAL_END;
-
- nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY_END, &nld.value,
- nld.len);
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len);
+ if (set->set_flags & NFT_SET_INTERVAL && key->field_count > 1) {
+ key->flags |= EXPR_F_INTERVAL_END;
+ netlink_gen_data(key, &nld);
+ key->flags &= ~EXPR_F_INTERVAL_END;
+
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY_END,
+ &nld.value, nld.len);
+ }
+ break;
}
if (elem->timeout)
@@ -209,8 +215,12 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
}
if (expr->flags & EXPR_F_INTERVAL_END)
- nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_FLAGS,
- NFT_SET_ELEM_INTERVAL_END);
+ flags |= NFT_SET_ELEM_INTERVAL_END;
+ if (key->etype == EXPR_SET_ELEM_CATCHALL)
+ flags |= NFT_SET_ELEM_CATCHALL;
+
+ if (flags)
+ nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_FLAGS, flags);
return nlse;
}
@@ -1133,25 +1143,34 @@ int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
init_list_head(&setelem_parse_ctx.stmt_list);
- nld.value =
- nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY, &nld.len);
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY))
+ nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY, &nld.len);
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_FLAGS))
flags = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_FLAGS);
key_end:
- key = netlink_alloc_value(&netlink_location, &nld);
- datatype_set(key, set->key->dtype);
- key->byteorder = set->key->byteorder;
- if (set->key->dtype->subtypes)
- key = netlink_parse_concat_elem(set->key->dtype, key);
-
- if (!(set->flags & NFT_SET_INTERVAL) &&
- 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 (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY)) {
+ key = netlink_alloc_value(&netlink_location, &nld);
+ datatype_set(key, set->key->dtype);
+ key->byteorder = set->key->byteorder;
+ if (set->key->dtype->subtypes)
+ key = netlink_parse_concat_elem(set->key->dtype, key);
+
+ if (!(set->flags & NFT_SET_INTERVAL) &&
+ 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);
+ } else if (flags & NFT_SET_ELEM_CATCHALL) {
+ key = set_elem_catchall_expr_alloc(&netlink_location);
+ datatype_set(key, set->key->dtype);
+ key->byteorder = set->key->byteorder;
+ key->len = set->key->len;
+ } else {
+ BUG("Unexpected set element with no key\n");
+ }
expr = set_elem_expr_alloc(&netlink_location, key);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index e4a5ade2..000eb40a 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -697,8 +697,8 @@ int nft_lex(void *, void *, void *);
%type <expr> multiton_stmt_expr
%destructor { expr_free($$); } multiton_stmt_expr
-%type <expr> prefix_stmt_expr range_stmt_expr wildcard_expr
-%destructor { expr_free($$); } prefix_stmt_expr range_stmt_expr wildcard_expr
+%type <expr> prefix_stmt_expr range_stmt_expr
+%destructor { expr_free($$); } prefix_stmt_expr range_stmt_expr
%type <expr> primary_stmt_expr basic_stmt_expr
%destructor { expr_free($$); } primary_stmt_expr basic_stmt_expr
@@ -3470,20 +3470,8 @@ range_stmt_expr : basic_stmt_expr DASH basic_stmt_expr
}
;
-wildcard_expr : ASTERISK
- {
- struct expr *expr;
-
- expr = constant_expr_alloc(&@$, &integer_type,
- BYTEORDER_HOST_ENDIAN,
- 0, NULL);
- $$ = prefix_expr_alloc(&@$, expr, 0);
- }
- ;
-
multiton_stmt_expr : prefix_stmt_expr
| range_stmt_expr
- | wildcard_expr
;
stmt_expr : map_stmt_expr
@@ -4088,6 +4076,7 @@ set_elem_expr : set_elem_expr_alloc
;
set_elem_key_expr : set_lhs_expr { $$ = $1; }
+ | ASTERISK { $$ = set_elem_catchall_expr_alloc(&@1); }
;
set_elem_expr_alloc : set_elem_key_expr set_elem_stmt_list
@@ -4227,7 +4216,6 @@ set_elem_expr_option : TIMEOUT time_spec
;
set_lhs_expr : concat_rhs_expr
- | wildcard_expr
;
set_rhs_expr : concat_rhs_expr
@@ -4500,7 +4488,6 @@ list_rhs_expr : basic_rhs_expr COMMA basic_rhs_expr
;
rhs_expr : concat_rhs_expr { $$ = $1; }
- | wildcard_expr { $$ = $1; }
| set_expr { $$ = $1; }
| set_ref_symbol_expr { $$ = $1; }
;
diff --git a/src/segtree.c b/src/segtree.c
index 353a0053..a4e047e7 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -618,10 +618,27 @@ int set_to_intervals(struct list_head *errs, struct set *set,
struct expr *init, bool add, unsigned int debug_mask,
bool merge, struct output_ctx *octx)
{
+ struct expr *catchall = NULL, *i, *in, *key;
struct elementary_interval *ei, *next;
struct seg_tree tree;
LIST_HEAD(list);
+ list_for_each_entry_safe(i, in, &init->expressions, list) {
+ if (i->etype == EXPR_MAPPING)
+ key = i->left->key;
+ else if (i->etype == EXPR_SET_ELEM)
+ key = i->key;
+ else
+ continue;
+
+ if (key->etype == EXPR_SET_ELEM_CATCHALL) {
+ init->size--;
+ catchall = i;
+ list_del(&i->list);
+ break;
+ }
+ }
+
seg_tree_init(&tree, set, init, debug_mask);
if (set_to_segtree(errs, set, init, &tree, add, merge) < 0)
return -1;
@@ -643,6 +660,11 @@ int set_to_intervals(struct list_head *errs, struct set *set,
pr_gmp_debug("\n");
}
+ if (catchall) {
+ list_add_tail(&catchall->list, &init->expressions);
+ init->size++;
+ }
+
return 0;
}
@@ -682,6 +704,9 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
i->flags |= EXPR_F_INTERVAL_END;
compound_expr_add(new_init, expr_clone(i));
break;
+ case EXPR_SET_ELEM_CATCHALL:
+ compound_expr_add(new_init, expr_clone(i));
+ break;
default:
range_expr_value_low(low, i);
set_elem_add(set, new_init, low, 0, i->byteorder);
@@ -941,8 +966,8 @@ next:
void interval_map_decompose(struct expr *set)
{
+ struct expr *i, *next, *low = NULL, *end, *catchall = NULL, *key;
struct expr **elements, **ranges;
- struct expr *i, *next, *low = NULL, *end;
unsigned int n, m, size;
mpz_t range, p;
bool interval;
@@ -959,6 +984,17 @@ void interval_map_decompose(struct expr *set)
/* Sort elements */
n = 0;
list_for_each_entry_safe(i, next, &set->expressions, list) {
+ key = NULL;
+ if (i->etype == EXPR_SET_ELEM)
+ key = i->key;
+ else if (i->etype == EXPR_MAPPING)
+ key = i->left->key;
+
+ if (key && key->etype == EXPR_SET_ELEM_CATCHALL) {
+ list_del(&i->list);
+ catchall = i;
+ continue;
+ }
compound_expr_remove(set, i);
elements[n++] = i;
}
@@ -1094,6 +1130,9 @@ void interval_map_decompose(struct expr *set)
compound_expr_add(set, i);
out:
+ if (catchall)
+ compound_expr_add(set, catchall);
+
mpz_clear(range);
mpz_clear(p);