From 419d196886889e9b37f76f8c803cb08dcbc05505 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 10 May 2021 18:52:45 +0200 Subject: 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 Signed-off-by: Pablo Neira Ayuso --- src/evaluate.c | 2 ++ src/expression.c | 24 ++++++++++++++++++ src/mergesort.c | 4 +++ src/netlink.c | 71 ++++++++++++++++++++++++++++++++++-------------------- src/parser_bison.y | 19 +++------------ src/segtree.c | 41 ++++++++++++++++++++++++++++++- 6 files changed, 118 insertions(+), 43 deletions(-) (limited to 'src') 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 multiton_stmt_expr %destructor { expr_free($$); } multiton_stmt_expr -%type prefix_stmt_expr range_stmt_expr wildcard_expr -%destructor { expr_free($$); } prefix_stmt_expr range_stmt_expr wildcard_expr +%type prefix_stmt_expr range_stmt_expr +%destructor { expr_free($$); } prefix_stmt_expr range_stmt_expr %type 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); -- cgit v1.2.3