EXPR_SET_ELEM provides the timeout, expiration, comment and list of statements, this is a shim expression. Currently, expr_set(x)->expressions can have either: - EXPR_SET_ELEM EXPR_SET_ELEM -> EXPR_VALUE - EXPR_MAPPING, which contains EXPR_SET_ELEM in the lhs. EXPR_SET_ELEM -> EXPR_VALUE / EXPR_MAPPING | \ EXPR_VALUE This patch normalizes the expression for mappings: EXPR_SET_ELEM -> EXPR_VALUE / EXPR_SET_ELEM -> EXPR_MAPPING | \ EXPR_VALUE The previous representation makes it natural for expr_print() to print the timeout, expiration, statements and comments. 1.1.1.1 counter packets 1 bytes 564 : 0x00000001, This patch adds an exception for expr_mapping_print() to stick to the existing representation. The JSON representation provides this set element information too in the lhs, which is does not really belong there because it is exposing transparently the syntax tree for set elements. A workaround to retain compatibility is included in this patch. The end goal is to replace EXPR_SET_ELEM by a smaller shim object, to further reduce memory consumption in set elements in userspace. Signed-off-by: Pablo Neira Ayuso --- include/expression.h | 4 +- src/datatype.c | 1 + src/evaluate.c | 68 +++++++++++--------- src/expression.c | 27 ++++++-- src/intervals.c | 126 ++++++++++++++++++++++---------------- src/json.c | 32 ++++++++-- src/netlink.c | 95 ++++++++++++++-------------- src/netlink_delinearize.c | 9 ++- src/optimize.c | 49 ++++++++------- src/parser_bison.y | 10 ++- src/parser_json.c | 14 +++-- src/segtree.c | 31 +++++----- 12 files changed, 282 insertions(+), 184 deletions(-) diff --git a/include/expression.h b/include/expression.h index e73ad90e7e5d..076a6a255228 100644 --- a/include/expression.h +++ b/include/expression.h @@ -563,7 +563,9 @@ extern struct expr *set_elem_expr_alloc(const struct location *loc, struct expr *set_elem_catchall_expr_alloc(const struct location *loc); #define expr_type_catchall(__expr) \ - ((__expr)->etype == EXPR_SET_ELEM_CATCHALL) + ((__expr)->etype == EXPR_SET_ELEM_CATCHALL || \ + ((__expr)->etype == EXPR_MAPPING && \ + (__expr)->left->etype == EXPR_SET_ELEM_CATCHALL)) 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/datatype.c b/src/datatype.c index f347010f4a1a..f130754fa338 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -1582,6 +1582,7 @@ const struct datatype boolean_type = { .name = "boolean", .desc = "boolean type", .size = 1, + .byteorder = BYTEORDER_HOST_ENDIAN, .parse = boolean_type_parse, .basetype = &integer_type, .sym_tbl = &boolean_tbl, diff --git a/src/evaluate.c b/src/evaluate.c index b7e4f71fdfbc..3ed6f1b3f8ca 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1932,6 +1932,9 @@ static bool elem_key_compatible(const struct expr *set_key, if (expr_type_catchall(elem_key)) return true; + if (elem_key->etype == EXPR_MAPPING) + return datatype_compatible(set_key->dtype, elem_key->left->dtype); + return datatype_compatible(set_key->dtype, elem_key->dtype); } @@ -2005,14 +2008,6 @@ static int expr_evaluate_set_elem_catchall(struct eval_ctx *ctx, struct expr **e return 0; } -static const struct expr *expr_set_elem(const struct expr *expr) -{ - if (expr->etype == EXPR_MAPPING) - return expr->left; - - return expr; -} - static int interval_set_eval(struct eval_ctx *ctx, struct set *set, struct expr *init) { @@ -2064,18 +2059,19 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) const struct expr *elem; list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) { + /* recursive EXPR_SET are merged here. */ if (list_member_evaluate(ctx, &i) < 0) return -1; - if (i->etype == EXPR_MAPPING && - i->left->etype == EXPR_SET_ELEM && - i->left->key->etype == EXPR_SET) { + if (i->key->etype == EXPR_MAPPING && + i->key->left->etype == EXPR_SET) { struct expr *new, *j; - list_for_each_entry(j, &expr_set(i->left->key)->expressions, list) { + list_for_each_entry(j, &expr_set(i->key->left)->expressions, list) { new = mapping_expr_alloc(&i->location, - expr_get(j), - expr_get(i->right)); + expr_get(j->key), + expr_get(i->key->right)); + new = set_elem_expr_alloc(&i->location, new); list_add_tail(&new->list, &expr_set(set)->expressions); expr_set(set)->size++; } @@ -2084,7 +2080,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) continue; } - elem = expr_set_elem(i); + elem = i; if (elem->etype == EXPR_SET_ELEM && elem->key->etype == EXPR_SET_REF) @@ -2099,7 +2095,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) list_replace(&i->list, &new->list); expr_free(i); i = new; - elem = expr_set_elem(i); + elem = i; } if (!expr_is_constant(i)) @@ -2115,7 +2111,9 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) expr_free(i); } else if (!expr_is_singleton(i)) { expr_set(set)->set_flags |= NFT_SET_INTERVAL; - if (elem->key->etype == EXPR_CONCAT) + if ((elem->key->etype == EXPR_MAPPING && + elem->key->left->etype == EXPR_CONCAT) || + elem->key->etype == EXPR_CONCAT) expr_set(set)->set_flags |= NFT_SET_CONCAT; } } @@ -2186,10 +2184,12 @@ static int mapping_expr_expand(struct eval_ctx *ctx) return 0; list_for_each_entry(i, &expr_set(ctx->set->init)->expressions, list) { - if (i->etype != EXPR_MAPPING) + assert(i->etype == EXPR_SET_ELEM); + + if (i->key->etype != EXPR_MAPPING) return expr_error(ctx->msgs, i, "expected mapping, not %s", expr_name(i)); - __mapping_expr_expand(i); + __mapping_expr_expand(i->key); } return 0; @@ -2378,6 +2378,7 @@ static bool elem_data_compatible(const struct expr *set_data, static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr) { + const struct expr *key = ctx->ectx.key; struct expr *mapping = *expr; struct set *set = ctx->set; uint32_t datalen; @@ -2389,6 +2390,8 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr) return set_error(ctx, set, "set is not a map"); expr_set_context(&ctx->ectx, set->key->dtype, set->key->len); + ctx->ectx.key = key; + if (expr_evaluate(ctx, &mapping->left) < 0) return -1; if (!expr_is_constant(mapping->left)) @@ -2691,11 +2694,15 @@ static int __binop_transfer(struct eval_ctx *ctx, break; case EXPR_SET: list_for_each_entry(i, &expr_set(*right)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + err = binop_can_transfer(ctx, left, i); if (err <= 0) return err; } list_for_each_entry_safe(i, next, &expr_set(*right)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + list_del(&i->list); err = binop_transfer_one(ctx, left, &i); list_add_tail(&i->list, &next->list); @@ -4463,8 +4470,10 @@ static bool nat_concat_map(struct eval_ctx *ctx, struct stmt *stmt) switch (stmt->nat.addr->mappings->etype) { case EXPR_SET: list_for_each_entry(i, &expr_set(stmt->nat.addr->mappings)->expressions, list) { - if (i->etype == EXPR_MAPPING && - i->right->etype == EXPR_CONCAT) { + assert(i->etype == EXPR_SET_ELEM); + + if (i->key->etype == EXPR_MAPPING && + i->key->right->etype == EXPR_CONCAT) { stmt->nat.type_flags |= STMT_NAT_F_CONCAT; return true; } @@ -5303,16 +5312,17 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set) } if (set_is_anonymous(set->flags) && set->key->etype == EXPR_CONCAT) { - struct expr *i; + struct expr *i, *key; list_for_each_entry(i, &expr_set(set->init)->expressions, list) { - if ((i->etype == EXPR_SET_ELEM && - i->key->etype != EXPR_CONCAT && - i->key->etype != EXPR_SET_ELEM_CATCHALL) || - (i->etype == EXPR_MAPPING && - i->left->etype == EXPR_SET_ELEM && - i->left->key->etype != EXPR_CONCAT && - i->left->key->etype != EXPR_SET_ELEM_CATCHALL)) + assert (i->etype == EXPR_SET_ELEM); + + key = i->key; + if (key->etype == EXPR_MAPPING) + key = key->left; + + if (key->etype != EXPR_CONCAT && + key->etype != EXPR_SET_ELEM_CATCHALL) return expr_error(ctx->msgs, i, "expression is not a concatenation"); } } diff --git a/src/expression.c b/src/expression.c index 019c263f187b..8b54b6a38ae5 100644 --- a/src/expression.c +++ b/src/expression.c @@ -1509,14 +1509,16 @@ struct expr *mapping_expr_alloc(const struct location *loc, static bool __set_expr_is_vmap(const struct expr *mappings) { - const struct expr *mapping; + const struct expr *elem; if (list_empty(&expr_set(mappings)->expressions)) return false; - mapping = list_first_entry(&expr_set(mappings)->expressions, struct expr, list); - if (mapping->etype == EXPR_MAPPING && - mapping->right->etype == EXPR_VERDICT) + elem = list_first_entry(&expr_set(mappings)->expressions, struct expr, list); + assert(elem->etype == EXPR_SET_ELEM); + + if (elem->key->etype == EXPR_MAPPING && + elem->key->right->etype == EXPR_VERDICT) return true; return false; @@ -1647,7 +1649,17 @@ static void set_elem_expr_print(const struct expr *expr, { struct stmt *stmt; - expr_print(expr->key, octx); + /* The mapping output needs to print lhs first, then timeout, expires, + * comment and list of statements and finally rhs. + * + * Because EXPR_SET_ELEM always comes before EXPR_MAPPING, add this + * special handling to print the output accordingly. + */ + if (expr->key->etype == EXPR_MAPPING) + expr_print(expr->key->left, octx); + else + expr_print(expr->key, octx); + list_for_each_entry(stmt, &expr->stmt_list, list) { nft_print(octx, " "); stmt_print(stmt, octx); @@ -1667,6 +1679,11 @@ static void set_elem_expr_print(const struct expr *expr, } if (expr->comment) nft_print(octx, " comment \"%s\"", expr->comment); + + if (expr->key->etype == EXPR_MAPPING) { + nft_print(octx, " : "); + expr_print(expr->key->right, octx); + } } static void set_elem_expr_destroy(struct expr *expr) diff --git a/src/intervals.c b/src/intervals.c index a63c58ac9606..7df5ce2ab4db 100644 --- a/src/intervals.c +++ b/src/intervals.c @@ -15,65 +15,73 @@ static void set_to_range(struct expr *init); -static void setelem_expr_to_range(struct expr *expr) +static void __setelem_expr_to_range(struct expr **exprp) { - struct expr *key; + struct expr *key, *expr = *exprp; mpz_t rop; - assert(expr->etype == EXPR_SET_ELEM); - - switch (expr->key->etype) { + switch (expr->etype) { case EXPR_SET_ELEM_CATCHALL: case EXPR_RANGE_VALUE: break; case EXPR_RANGE: key = constant_range_expr_alloc(&expr->location, - expr->key->dtype, - expr->key->byteorder, - expr->key->len, - expr->key->left->value, - expr->key->right->value); - expr_free(expr->key); - expr->key = key; + expr->dtype, + expr->byteorder, + expr->len, + expr->left->value, + expr->right->value); + expr_free(*exprp); + *exprp = key; break; case EXPR_PREFIX: - if (expr->key->prefix->etype != EXPR_VALUE) - BUG("Prefix for unexpected type %d", expr->key->prefix->etype); + if (expr->prefix->etype != EXPR_VALUE) + BUG("Prefix for unexpected type %d", expr->prefix->etype); mpz_init(rop); - mpz_bitmask(rop, expr->key->len - expr->key->prefix_len); + mpz_bitmask(rop, expr->len - expr->prefix_len); if (expr_basetype(expr)->type == TYPE_STRING) - mpz_switch_byteorder(expr->key->prefix->value, expr->len / BITS_PER_BYTE); + mpz_switch_byteorder(expr->prefix->value, expr->len / BITS_PER_BYTE); - mpz_ior(rop, rop, expr->key->prefix->value); + mpz_ior(rop, rop, expr->prefix->value); key = constant_range_expr_alloc(&expr->location, - expr->key->dtype, - expr->key->byteorder, - expr->key->len, - expr->key->prefix->value, + expr->dtype, + expr->byteorder, + expr->len, + expr->prefix->value, rop); mpz_clear(rop); - expr_free(expr->key); - expr->key = key; + expr_free(*exprp); + *exprp = key; break; case EXPR_VALUE: if (expr_basetype(expr)->type == TYPE_STRING) - mpz_switch_byteorder(expr->key->value, expr->len / BITS_PER_BYTE); + mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE); key = constant_range_expr_alloc(&expr->location, - expr->key->dtype, - expr->key->byteorder, - expr->key->len, - expr->key->value, - expr->key->value); - expr_free(expr->key); - expr->key = key; + expr->dtype, + expr->byteorder, + expr->len, + expr->value, + expr->value); + expr_free(*exprp); + *exprp = key; break; default: - BUG("unhandled key type %s\n", expr_name(expr->key)); + BUG("unhandled key type %s\n", expr_name(expr)); } } +static void setelem_expr_to_range(struct expr *expr) +{ + assert(expr->etype == EXPR_SET_ELEM); + + if (expr->key->etype == EXPR_MAPPING) + __setelem_expr_to_range(&expr->key->left); + else + __setelem_expr_to_range(&expr->key); +} + struct set_automerge_ctx { struct set *set; struct expr *init; @@ -219,9 +227,6 @@ static struct expr *interval_expr_key(struct expr *i) struct expr *elem; switch (i->etype) { - case EXPR_MAPPING: - elem = i->left; - break; case EXPR_SET_ELEM: elem = i; break; @@ -411,9 +416,17 @@ static int setelem_delete(struct list_head *msgs, struct set *set, i = interval_expr_key(elem); if (expr_type_catchall(i->key)) { + uint32_t len; + /* Assume max value to simplify handling. */ - mpz_bitmask(range.low, i->len); - mpz_bitmask(range.high, i->len); + if (i->key->etype == EXPR_SET_ELEM_CATCHALL) + len = i->key->len; + else if (i->key->etype == EXPR_MAPPING && + i->key->left->etype == EXPR_SET_ELEM_CATCHALL) + len = i->key->left->len; + + mpz_bitmask(range.low, len); + mpz_bitmask(range.high, len); } else { range_expr_value_low(range.low, i); range_expr_value_high(range.high, i); @@ -677,6 +690,20 @@ static bool segtree_needs_first_segment(const struct set *set, return false; } +static bool range_low_is_non_zero(const struct expr *expr) +{ + switch (expr->etype) { + case EXPR_RANGE_VALUE: + return mpz_cmp_ui(expr->range.low, 0); + case EXPR_MAPPING: + return range_low_is_non_zero(expr->left); + default: + BUG("unexpected expression %s\n", expr_name(expr)); + break; + } + return false; +} + int set_to_intervals(const struct set *set, struct expr *init, bool add) { struct expr *i, *n, *prev = NULL, *elem, *root, *expr; @@ -693,7 +720,7 @@ int set_to_intervals(const struct set *set, struct expr *init, bool add) break; if (segtree_needs_first_segment(set, init, add) && - mpz_cmp_ui(elem->key->range.low, 0)) { + range_low_is_non_zero(elem->key)) { mpz_init2(p, set->key->len); mpz_set_ui(p, 0); expr = constant_range_expr_alloc(&internal_location, @@ -703,11 +730,7 @@ int set_to_intervals(const struct set *set, struct expr *init, bool add) mpz_clear(p); root = set_elem_expr_alloc(&internal_location, expr); - if (i->etype == EXPR_MAPPING) { - root = mapping_expr_alloc(&internal_location, - root, - expr_get(i->right)); - } + root->flags |= EXPR_F_INTERVAL_END; list_add(&root->list, &intervals); break; @@ -749,12 +772,11 @@ static struct expr *setelem_key(struct expr *expr) struct expr *key; switch (expr->etype) { - case EXPR_MAPPING: - key = expr->left->key; - break; case EXPR_SET_ELEM: - key = expr->key; - break; + if (expr->key->etype == EXPR_MAPPING) + return expr->key->left; + + return expr->key; default: BUG("unhandled expression type %d\n", expr->etype); return NULL; @@ -804,13 +826,13 @@ int setelem_to_interval(const struct set *set, struct expr *elem, if (set->key->byteorder == BYTEORDER_HOST_ENDIAN) mpz_switch_byteorder(low->value, set->key->len / BITS_PER_BYTE); + if (elem->key->etype == EXPR_MAPPING) + low = mapping_expr_alloc(&elem->location, + low, expr_get(elem->key->right)); + low = set_elem_expr_alloc(&key->location, low); set_elem_expr_copy(low, interval_expr_key(elem)); - if (elem->etype == EXPR_MAPPING) - low = mapping_expr_alloc(&elem->location, - low, expr_get(elem->right)); - list_add_tail(&low->list, intervals); if (adjacent) diff --git a/src/json.c b/src/json.c index d06fd0402714..36c03e581b4a 100644 --- a/src/json.c +++ b/src/json.c @@ -778,18 +778,19 @@ json_t *set_ref_expr_json(const struct expr *expr, struct output_ctx *octx) } } -json_t *set_elem_expr_json(const struct expr *expr, struct output_ctx *octx) +static json_t *__set_elem_expr_json(const struct expr *expr, + const struct expr *val, + struct output_ctx *octx) { - json_t *root = expr_print_json(expr->key, octx); + json_t *root = expr_print_json(val, octx); struct stmt *stmt; json_t *tmp; - if (!root) - return NULL; - /* these element attributes require formal set elem syntax */ if (expr->timeout || expr->expiration || expr->comment || !list_empty(&expr->stmt_list)) { + assert(expr->etype == EXPR_SET_ELEM); + root = nft_json_pack("{s:o}", "val", root); if (expr->timeout) { @@ -818,6 +819,27 @@ json_t *set_elem_expr_json(const struct expr *expr, struct output_ctx *octx) return root; } +json_t *set_elem_expr_json(const struct expr *expr, struct output_ctx *octx) +{ + json_t *left, *right; + + assert(expr->etype == EXPR_SET_ELEM); + + /* Special handling to retain backwards compatibility: json exposes + * EXPR_MAPPING { left: EXPR_SET_ELEM, right: EXPR_{VALUE,CONCAT,SYMBOL}. + * Revisit this at some point to accept the following input: + * EXPR_SET_ELEM -> EXPR_MAPPING { left, right } + */ + if (expr->key->etype == EXPR_MAPPING) { + left = __set_elem_expr_json(expr, expr->key->left, octx); + right = expr_print_json(expr->key->right, octx); + + return nft_json_pack("[o, o]", left, right); + } + + return __set_elem_expr_json(expr, expr->key, octx); +} + json_t *prefix_expr_json(const struct expr *expr, struct output_ctx *octx) { json_t *root = expr_print_json(expr->prefix, octx); diff --git a/src/netlink.c b/src/netlink.c index 5876c08929f7..10817e5cfb53 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -102,7 +102,7 @@ static void __netlink_gen_data(const struct expr *expr, struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set, const struct expr *expr) { - const struct expr *elem, *data; + const struct expr *data, *elem; struct nftnl_set_elem *nlse; struct nft_data_linearize nld; struct nftnl_udata_buf *udbuf = NULL; @@ -115,18 +115,20 @@ struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set, if (nlse == NULL) memory_allocation_error(); + if (expr->etype != EXPR_SET_ELEM) + BUG("Unexpected expression type: got %d\n", expr->etype); + data = NULL; - if (expr->etype == EXPR_MAPPING) { - elem = expr->left; - if (!(expr->flags & EXPR_F_INTERVAL_END)) - data = expr->right; + if (expr->key->etype == EXPR_MAPPING) { + if (!(expr->key->flags & EXPR_F_INTERVAL_END)) + data = expr->key->right; + + key = expr->key->left; } else { - elem = expr; + key = expr->key; } - if (elem->etype != EXPR_SET_ELEM) - BUG("Unexpected expression type: got %d\n", elem->etype); - key = elem->key; + elem = expr; switch (key->etype) { case EXPR_SET_ELEM_CATCHALL: @@ -571,6 +573,8 @@ static void netlink_gen_key(const struct expr *expr, return netlink_gen_range(expr, data); case EXPR_PREFIX: return netlink_gen_prefix(expr, data); + case EXPR_MAPPING: + return netlink_gen_key(expr->left, data); default: BUG("invalid data expression type %s\n", expr_name(expr)); } @@ -1509,41 +1513,6 @@ key_end: return 0; } - expr = set_elem_expr_alloc(&netlink_location, key); - expr->flags |= EXPR_F_KERNEL; - - if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT)) { - expr->timeout = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_TIMEOUT); - if (expr->timeout == 0) - expr->timeout = NFT_NEVER_TIMEOUT; - } - - if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPIRATION)) - expr->expiration = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_EXPIRATION); - if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_USERDATA)) { - set_elem_parse_udata(nlse, expr); - if (expr->comment) - set->elem_has_comment = true; - } - if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPR)) { - const struct nftnl_expr *nle; - struct stmt *stmt; - - nle = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_EXPR, NULL); - stmt = netlink_parse_set_expr(set, &ctx->nft->cache, nle); - list_add_tail(&stmt->list, &setelem_parse_ctx.stmt_list); - } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPRESSIONS)) { - nftnl_set_elem_expr_foreach(nlse, set_elem_parse_expressions, - &setelem_parse_ctx); - } - list_splice_tail_init(&setelem_parse_ctx.stmt_list, &expr->stmt_list); - - if (flags & NFT_SET_ELEM_INTERVAL_END) { - expr->flags |= EXPR_F_INTERVAL_END; - if (mpz_cmp_ui(set->key->value, 0) == 0) - set->root = true; - } - if (set_is_datamap(set->flags)) { if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_DATA)) { nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_DATA, @@ -1574,7 +1543,7 @@ key_end: if (data->byteorder == BYTEORDER_HOST_ENDIAN) mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE); - expr = mapping_expr_alloc(&netlink_location, expr, data); + key = mapping_expr_alloc(&netlink_location, key, data); } if (set_is_objmap(set->flags)) { if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_OBJREF)) { @@ -1588,9 +1557,43 @@ key_end: data->dtype = &string_type; data->byteorder = BYTEORDER_HOST_ENDIAN; mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE); - expr = mapping_expr_alloc(&netlink_location, expr, data); + key = mapping_expr_alloc(&netlink_location, key, data); } out: + expr = set_elem_expr_alloc(&netlink_location, key); + expr->flags |= EXPR_F_KERNEL; + + if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT)) { + expr->timeout = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_TIMEOUT); + if (expr->timeout == 0) + expr->timeout = NFT_NEVER_TIMEOUT; + } + + if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPIRATION)) + expr->expiration = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_EXPIRATION); + if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_USERDATA)) { + set_elem_parse_udata(nlse, expr); + if (expr->comment) + set->elem_has_comment = true; + } + if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPR)) { + const struct nftnl_expr *nle; + struct stmt *stmt; + + nle = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_EXPR, NULL); + stmt = netlink_parse_set_expr(set, &ctx->nft->cache, nle); + list_add_tail(&stmt->list, &setelem_parse_ctx.stmt_list); + } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPRESSIONS)) { + nftnl_set_elem_expr_foreach(nlse, set_elem_parse_expressions, + &setelem_parse_ctx); + } + list_splice_tail_init(&setelem_parse_ctx.stmt_list, &expr->stmt_list); + + if (flags & NFT_SET_ELEM_INTERVAL_END) { + expr->flags |= EXPR_F_INTERVAL_END; + if (mpz_cmp_ui(set->key->value, 0) == 0) + set->root = true; + } set_expr_add(set->init, expr); if (!(flags & NFT_SET_ELEM_INTERVAL_END) && diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 990edc824ad9..f4ebdfcbf2f3 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -2493,6 +2493,8 @@ static void binop_adjust(const struct expr *binop, struct expr *right, break; list_for_each_entry(i, &expr_set(right->set->init)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + switch (i->key->etype) { case EXPR_VALUE: binop_adjust_one(binop, i->key, shift); @@ -2501,8 +2503,11 @@ static void binop_adjust(const struct expr *binop, struct expr *right, binop_adjust_one(binop, i->key->left, shift); binop_adjust_one(binop, i->key->right, shift); break; - case EXPR_SET_ELEM: - binop_adjust(binop, i->key->key, shift); + case EXPR_MAPPING: + if (i->key->left->etype == EXPR_RANGE) + binop_adjust(binop, i->key->left, shift); + else + binop_adjust_one(binop, i->key->left, shift); break; default: BUG("unknown expression type %s\n", expr_name(i->key)); diff --git a/src/optimize.c b/src/optimize.c index cdd6913a306d..422990d1ca6f 100644 --- a/src/optimize.c +++ b/src/optimize.c @@ -751,29 +751,31 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict, switch (expr->etype) { case EXPR_LIST: list_for_each_entry(item, &expr_list(expr)->expressions, list) { - elem = set_elem_expr_alloc(&internal_location, expr_get(item)); + mapping = mapping_expr_alloc(&internal_location, expr_get(item), + expr_get(verdict->expr)); + + elem = set_elem_expr_alloc(&internal_location, mapping); if (counter) { counter_elem = counter_stmt_alloc(&counter->location); list_add_tail(&counter_elem->list, &elem->stmt_list); } - mapping = mapping_expr_alloc(&internal_location, elem, - expr_get(verdict->expr)); - set_expr_add(set, mapping); + set_expr_add(set, elem); } stmt_free(counter); break; case EXPR_SET: list_for_each_entry(item, &expr_set(expr)->expressions, list) { - elem = set_elem_expr_alloc(&internal_location, expr_get(item->key)); + mapping = mapping_expr_alloc(&internal_location, expr_get(item->key), + expr_get(verdict->expr)); + + elem = set_elem_expr_alloc(&internal_location, mapping); if (counter) { counter_elem = counter_stmt_alloc(&counter->location); list_add_tail(&counter_elem->list, &elem->stmt_list); } - mapping = mapping_expr_alloc(&internal_location, elem, - expr_get(verdict->expr)); - set_expr_add(set, mapping); + set_expr_add(set, elem); } stmt_free(counter); break; @@ -784,13 +786,14 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict, case EXPR_VALUE: case EXPR_SYMBOL: case EXPR_CONCAT: - elem = set_elem_expr_alloc(&internal_location, expr_get(expr)); + mapping = mapping_expr_alloc(&internal_location, expr_get(expr), + expr_get(verdict->expr)); + + elem = set_elem_expr_alloc(&internal_location, mapping); if (counter) list_add_tail(&counter->list, &elem->stmt_list); - mapping = mapping_expr_alloc(&internal_location, elem, - expr_get(verdict->expr)); - set_expr_add(set, mapping); + set_expr_add(set, elem); break; default: assert(0); @@ -890,15 +893,17 @@ static void __merge_concat_stmts_vmap(const struct optimize_ctx *ctx, list_for_each_entry_safe(concat, next, &concat_list, list) { list_del(&concat->list); - elem = set_elem_expr_alloc(&internal_location, concat); + + mapping = mapping_expr_alloc(&internal_location, concat, + expr_get(verdict->expr)); + + elem = set_elem_expr_alloc(&internal_location, mapping); if (counter) { counter_elem = counter_stmt_alloc(&counter->location); list_add_tail(&counter_elem->list, &elem->stmt_list); } - mapping = mapping_expr_alloc(&internal_location, elem, - expr_get(verdict->expr)); - set_expr_add(set, mapping); + set_expr_add(set, elem); } stmt_free(counter); } @@ -1059,9 +1064,9 @@ static void merge_nat(const struct optimize_ctx *ctx, nat_stmt = ctx->stmt_matrix[i][k]; nat_expr = stmt_nat_expr(nat_stmt); - elem = set_elem_expr_alloc(&internal_location, expr_get(expr)); - mapping = mapping_expr_alloc(&internal_location, elem, nat_expr); - set_expr_add(set, mapping); + mapping = mapping_expr_alloc(&internal_location, expr_get(expr), nat_expr); + elem = set_elem_expr_alloc(&internal_location, mapping); + set_expr_add(set, elem); } stmt = ctx->stmt_matrix[from][merge->stmt[0]]; @@ -1116,9 +1121,9 @@ static void merge_concat_nat(const struct optimize_ctx *ctx, nat_stmt = ctx->stmt_matrix[i][k]; nat_expr = stmt_nat_expr(nat_stmt); - elem = set_elem_expr_alloc(&internal_location, concat); - mapping = mapping_expr_alloc(&internal_location, elem, nat_expr); - set_expr_add(set, mapping); + mapping = mapping_expr_alloc(&internal_location, concat, nat_expr); + elem = set_elem_expr_alloc(&internal_location, mapping); + set_expr_add(set, elem); } concat = concat_expr_alloc(&internal_location); diff --git a/src/parser_bison.y b/src/parser_bison.y index 3fa75197d1cb..d0cb2f7f929f 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -3337,7 +3337,10 @@ verdict_map_list_expr : verdict_map_list_member_expr verdict_map_list_member_expr: opt_newline set_elem_expr COLON verdict_expr opt_newline { - $$ = mapping_expr_alloc(&@2, $2, $4); + struct expr *expr = $2; + + expr->key = mapping_expr_alloc(&@2, $2->key, $4); + $$ = expr; } ; @@ -4604,7 +4607,10 @@ set_list_member_expr : opt_newline set_expr opt_newline } | opt_newline set_elem_expr COLON set_rhs_expr opt_newline { - $$ = mapping_expr_alloc(&@2, $2, $4); + struct expr *expr = $2; + + expr->key = mapping_expr_alloc(&@2, $2->key, $4); + $$ = expr; } ; diff --git a/src/parser_json.c b/src/parser_json.c index e78262505d24..875b4b8a5f18 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -1476,7 +1476,7 @@ static struct expr *json_parse_set_expr(struct json_ctx *ctx, } json_array_foreach(root, index, value) { - struct expr *expr; + struct expr *expr, *elem; json_t *jleft, *jright; if (!json_unpack(value, "[o, o!]", &jleft, &jright)) { @@ -1488,8 +1488,13 @@ static struct expr *json_parse_set_expr(struct json_ctx *ctx, expr_free(set_expr); return NULL; } - if (expr->etype != EXPR_SET_ELEM) - expr = set_elem_expr_alloc(int_loc, expr); + + if (expr->etype != EXPR_SET_ELEM) { + elem = set_elem_expr_alloc(int_loc, expr); + } else { + elem = expr; + expr = expr->key; + } expr2 = json_parse_set_rhs_expr(ctx, jright); if (!expr2) { @@ -1499,7 +1504,8 @@ static struct expr *json_parse_set_expr(struct json_ctx *ctx, return NULL; } expr2 = mapping_expr_alloc(int_loc, expr, expr2); - expr = expr2; + elem->key = expr2; + expr = elem; } else { expr = json_parse_rhs_expr(ctx, value); diff --git a/src/segtree.c b/src/segtree.c index 88207a3987b8..b5be0005d1ea 100644 --- a/src/segtree.c +++ b/src/segtree.c @@ -113,9 +113,10 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init) static struct expr *expr_value(struct expr *expr) { switch (expr->etype) { - case EXPR_MAPPING: - return expr->left->key; case EXPR_SET_ELEM: + if (expr->key->etype == EXPR_MAPPING) + return expr->key->left; + return expr->key; case EXPR_VALUE: return expr; @@ -167,17 +168,16 @@ out: static struct expr *__expr_to_set_elem(struct expr *low, struct expr *expr) { - struct expr *elem = set_elem_expr_alloc(&low->location, expr); - - if (low->etype == EXPR_MAPPING) { - interval_expr_copy(elem, low->left); + struct expr *elem; - elem = mapping_expr_alloc(&low->location, elem, - expr_clone(low->right)); - } else { - interval_expr_copy(elem, low); + if (low->key->etype == EXPR_MAPPING) { + expr = mapping_expr_alloc(&low->location, expr, + expr_clone(low->key->right)); } + + elem = set_elem_expr_alloc(&low->location, expr); elem->flags |= EXPR_F_KERNEL; + interval_expr_copy(elem, low); return elem; } @@ -237,6 +237,8 @@ int get_set_decompose(struct set *cache_set, struct set *set) new_init = set_expr_alloc(&internal_location, set); list_for_each_entry_safe(i, next, &expr_set(set->init)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + if (i->flags & EXPR_F_INTERVAL_END && left) { list_del(&left->list); list_del(&i->list); @@ -573,13 +575,10 @@ void interval_map_decompose(struct expr *set) /* Sort elements */ n = 0; list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) { - key = NULL; - if (i->etype == EXPR_SET_ELEM) - key = i->key; - else if (i->etype == EXPR_MAPPING) - key = i->left->key; + assert(i->etype == EXPR_SET_ELEM); - if (key && expr_type_catchall(key)) { + key = i->key; + if (expr_type_catchall(key)) { list_del(&i->list); catchall = i; continue; -- 2.30.2 Normalize the representation so the expressions list in EXPR_SET always contains EXPR_SET_ELEM. Add assert() to validate this. Signed-off-by: Pablo Neira Ayuso --- src/evaluate.c | 3 ++- src/parser_bison.y | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/evaluate.c b/src/evaluate.c index 3ed6f1b3f8ca..b0a3e990e476 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2059,7 +2059,8 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) const struct expr *elem; list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) { - /* recursive EXPR_SET are merged here. */ + assert(i->etype == EXPR_SET_ELEM); + if (list_member_evaluate(ctx, &i) < 0) return -1; diff --git a/src/parser_bison.y b/src/parser_bison.y index d0cb2f7f929f..dcbdc4514298 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -4599,7 +4599,7 @@ set_list_expr : set_list_member_expr set_list_member_expr : opt_newline set_expr opt_newline { - $$ = $2; + $$ = set_elem_expr_alloc(&@$, $2); } | opt_newline set_elem_expr opt_newline { -- 2.30.2 Normalize the representation so the expressions list in EXPR_SET always contains EXPR_SET_ELEM. Add assert() to validate this. Signed-off-by: Pablo Neira Ayuso --- src/evaluate.c | 23 +++++++++-------------- src/expression.c | 16 ++++++++++++---- src/intervals.c | 14 ++++++++++++++ src/json.c | 10 ++++++++-- src/netlink.c | 2 ++ src/netlink_delinearize.c | 9 ++++++--- src/optimize.c | 3 +++ src/segtree.c | 6 ++++++ 8 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/evaluate.c b/src/evaluate.c index b0a3e990e476..0b7508a18ede 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2069,6 +2069,8 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) struct expr *new, *j; list_for_each_entry(j, &expr_set(i->key->left)->expressions, list) { + assert(j->etype == EXPR_SET_ELEM); + new = mapping_expr_alloc(&i->location, expr_get(j->key), expr_get(i->key->right)); @@ -2770,9 +2772,9 @@ static void optimize_singleton_set(struct expr *rel, struct expr **expr) struct expr *set = rel->right, *i; i = list_first_entry(&expr_set(set)->expressions, struct expr, list); - if (i->etype == EXPR_SET_ELEM && - list_empty(&i->stmt_list)) { + assert (i->etype == EXPR_SET_ELEM); + if (list_empty(&i->stmt_list)) { switch (i->key->etype) { case EXPR_PREFIX: case EXPR_RANGE: @@ -5476,19 +5478,12 @@ static struct expr *expr_set_to_list(struct eval_ctx *ctx, struct expr *dev_expr LIST_HEAD(tmp); list_for_each_entry_safe(expr, next, &expr_set(dev_expr)->expressions, list) { - list_del(&expr->list); - - switch (expr->etype) { - case EXPR_SET_ELEM: - key = expr_clone(expr->key); - expr_free(expr); - expr = key; - break; - default: - BUG("invalid expression type %s\n", expr_name(expr)); - break; - } + assert(expr->etype == EXPR_SET_ELEM); + list_del(&expr->list); + key = expr_clone(expr->key); + expr_free(expr); + expr = key; list_add(&expr->list, &tmp); } diff --git a/src/expression.c b/src/expression.c index 8b54b6a38ae5..68e2fec192b2 100644 --- a/src/expression.c +++ b/src/expression.c @@ -941,8 +941,9 @@ void relational_expr_pctx_update(struct proto_ctx *ctx, ops->pctx_update(ctx, &expr->location, left, right); else if (right->etype == EXPR_SET) { list_for_each_entry(i, &expr_set(right)->expressions, list) { - if (i->etype == EXPR_SET_ELEM && - i->key->etype == EXPR_VALUE) + assert(i->etype == EXPR_SET_ELEM); + + if (i->key->etype == EXPR_VALUE) ops->pctx_update(ctx, &expr->location, left, i->key); } } else if (ops == &meta_expr_ops && @@ -1378,6 +1379,8 @@ static void set_expr_print(const struct expr *expr, struct output_ctx *octx) nft_print(octx, "{ "); list_for_each_entry(i, &expr_set(expr)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + nft_print(octx, "%s", d); expr_print(i, octx); count++; @@ -1400,8 +1403,10 @@ static void set_expr_destroy(struct expr *expr) { struct expr *i, *next; - list_for_each_entry_safe(i, next, &expr_set(expr)->expressions, list) + list_for_each_entry_safe(i, next, &expr_set(expr)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); expr_free(i); + } } static void set_expr_set_type(const struct expr *expr, @@ -1410,8 +1415,11 @@ static void set_expr_set_type(const struct expr *expr, { struct expr *i; - list_for_each_entry(i, &expr_set(expr)->expressions, list) + list_for_each_entry(i, &expr_set(expr)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + expr_set_type(i, dtype, byteorder); + } } static const struct expr_ops set_expr_ops = { diff --git a/src/intervals.c b/src/intervals.c index 7df5ce2ab4db..3ac45cf29abd 100644 --- a/src/intervals.c +++ b/src/intervals.c @@ -183,6 +183,8 @@ static void setelem_automerge(struct set_automerge_ctx *ctx) mpz_init(rop); list_for_each_entry_safe(i, next, &expr_set(ctx->init)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + if (expr_type_catchall(i->key)) continue; @@ -243,6 +245,8 @@ static void set_to_range(struct expr *init) struct expr *i, *elem; list_for_each_entry(i, &expr_set(init)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + elem = interval_expr_key(i); setelem_expr_to_range(elem); } @@ -274,6 +278,8 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set, setelem_automerge(&ctx); list_for_each_entry_safe(i, next, &expr_set(init)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + if (i->flags & EXPR_F_KERNEL) { list_move_tail(&i->list, &expr_set(existing_set->init)->expressions); } else if (existing_set) { @@ -413,6 +419,8 @@ static int setelem_delete(struct list_head *msgs, struct set *set, mpz_init(rop); list_for_each_entry_safe(elem, next, &expr_set(elems)->expressions, list) { + assert(elem->etype == EXPR_SET_ELEM); + i = interval_expr_key(elem); if (expr_type_catchall(i->key)) { @@ -585,6 +593,8 @@ static int setelem_overlap(struct list_head *msgs, struct set *set, mpz_init(rop); list_for_each_entry_safe(elem, next, &expr_set(init)->expressions, list) { + assert(elem->etype == EXPR_SET_ELEM); + i = interval_expr_key(elem); if (expr_type_catchall(i->key)) @@ -654,6 +664,8 @@ int set_overlap(struct list_head *msgs, struct set *set, struct expr *init) err = setelem_overlap(msgs, set, init); list_for_each_entry_safe(i, n, &expr_set(init)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + if (i->flags & EXPR_F_KERNEL) list_move_tail(&i->list, &expr_set(existing_set->init)->expressions); else if (existing_set) { @@ -711,6 +723,8 @@ int set_to_intervals(const struct set *set, struct expr *init, bool add) mpz_t p; list_for_each_entry_safe(i, n, &expr_set(init)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + elem = interval_expr_key(i); if (expr_type_catchall(elem->key)) diff --git a/src/json.c b/src/json.c index 36c03e581b4a..612e8e6999eb 100644 --- a/src/json.c +++ b/src/json.c @@ -232,8 +232,11 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set) json_t *array = json_array(); const struct expr *i; - list_for_each_entry(i, &expr_set(set->init)->expressions, list) + list_for_each_entry(i, &expr_set(set->init)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + json_array_append_new(array, expr_print_json(i, octx)); + } json_object_set_new(root, "elem", array); } @@ -763,8 +766,11 @@ json_t *set_expr_json(const struct expr *expr, struct output_ctx *octx) json_t *array = json_array(); const struct expr *i; - list_for_each_entry(i, &expr_set(expr)->expressions, list) + list_for_each_entry(i, &expr_set(expr)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + json_array_append_new(array, expr_print_json(i, octx)); + } return nft_json_pack("{s:o}", "set", array); } diff --git a/src/netlink.c b/src/netlink.c index 10817e5cfb53..7a17f394c69f 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1219,6 +1219,8 @@ void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls) const struct expr *expr; list_for_each_entry(expr, &expr_set(set)->expressions, list) { + assert(expr->etype == EXPR_SET_ELEM); + nlse = alloc_nftnl_setelem(set, expr); nftnl_set_elem_add(nls, nlse); } diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index f4ebdfcbf2f3..3db5502910ad 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -2206,9 +2206,9 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx, struct expr *elem; elem = list_first_entry(&expr_set(set->init)->expressions, struct expr, list); + assert(elem->etype == EXPR_SET_ELEM); - if (elem->etype == EXPR_SET_ELEM && - elem->key->etype == EXPR_VALUE) + if (elem->key->etype == EXPR_VALUE) payload_icmp_check(ctx, payload, elem->key); } } @@ -2882,8 +2882,11 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) expr_postprocess(ctx, &expr->right); break; case EXPR_SET: - list_for_each_entry(i, &expr_set(expr)->expressions, list) + list_for_each_entry(i, &expr_set(expr)->expressions, list) { + assert(i->etype == EXPR_SET); + expr_postprocess(ctx, &i); + } break; case EXPR_CONCAT: expr_postprocess_concat(ctx, exprp); diff --git a/src/optimize.c b/src/optimize.c index 422990d1ca6f..e537f48adf58 100644 --- a/src/optimize.c +++ b/src/optimize.c @@ -589,6 +589,7 @@ static void merge_vmap(const struct optimize_ctx *ctx, mappings = stmt_b->expr->mappings; list_for_each_entry(expr, &expr_set(mappings)->expressions, list) { + assert(expr->etype == EXPR_SET_ELEM); mapping = expr_clone(expr); set_expr_add(stmt_a->expr->mappings, mapping); } @@ -655,6 +656,7 @@ static void __merge_concat(const struct optimize_ctx *ctx, uint32_t i, switch (stmt_a->expr->right->etype) { case EXPR_SET: list_for_each_entry(expr, &expr_set(stmt_a->expr->right)->expressions, list) { + assert(expr->etype == EXPR_SET_ELEM); concat_clone = expr_clone(concat); clone = expr_clone(expr->key); concat_expr_add(concat_clone, clone); @@ -766,6 +768,7 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict, break; case EXPR_SET: list_for_each_entry(item, &expr_set(expr)->expressions, list) { + assert(item->etype == EXPR_SET_ELEM); mapping = mapping_expr_alloc(&internal_location, expr_get(item->key), expr_get(verdict->expr)); diff --git a/src/segtree.c b/src/segtree.c index b5be0005d1ea..f95a7ce1c8a8 100644 --- a/src/segtree.c +++ b/src/segtree.c @@ -80,6 +80,8 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init) new_init = set_expr_alloc(&internal_location, NULL); list_for_each_entry(i, &expr_set(init)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + switch (i->key->etype) { case EXPR_VALUE: set_elem_add(set, new_init, i->key->value, @@ -137,6 +139,8 @@ static struct expr *get_set_interval_find(const struct set *cache_set, mpz_init2(val, set->key->len); list_for_each_entry(i, &expr_set(set->init)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + key = expr_value(i); switch (key->etype) { case EXPR_VALUE: @@ -357,6 +361,8 @@ void concat_range_aggregate(struct expr *set) mpz_t range, p; list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) { + assert(i->etype == EXPR_SET_ELEM); + if (!start) { start = i; continue; -- 2.30.2 After normalizing set element representation for EXPR_MAPPING, it is possible to simplify: a6b75b837f5e ("evaluate: set: Allow for set elems to be sets") Extend tests/shell coverage to exercise merging nested sets. Signed-off-by: Pablo Neira Ayuso --- src/evaluate.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/evaluate.c b/src/evaluate.c index 0b7508a18ede..85c446a124ee 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2090,27 +2090,17 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) return expr_error(ctx->msgs, i, "Set reference cannot be part of another set"); - if (elem->etype == EXPR_SET_ELEM && - elem->key->etype == EXPR_SET) { - struct expr *new = expr_get(elem->key); - - expr_set(set)->set_flags |= expr_set(elem->key)->set_flags; - list_replace(&i->list, &new->list); - expr_free(i); - i = new; - elem = i; - } - if (!expr_is_constant(i)) return expr_error(ctx->msgs, i, "Set member is not constant"); - if (i->etype == EXPR_SET) { + if (i->etype == EXPR_SET_ELEM && + i->key->etype == EXPR_SET) { /* Merge recursive set definitions */ - list_splice_tail_init(&expr_set(i)->expressions, &i->list); + list_splice_tail_init(&expr_set(i->key)->expressions, &i->list); list_del(&i->list); - expr_set(set)->size += expr_set(i)->size - 1; - expr_set(set)->set_flags |= expr_set(i)->set_flags; + expr_set(set)->size += expr_set(i->key)->size - 1; + expr_set(set)->set_flags |= expr_set(i->key)->set_flags; expr_free(i); } else if (!expr_is_singleton(i)) { expr_set(set)->set_flags |= NFT_SET_INTERVAL; -- 2.30.2 Remove redundant check for elem->etype == EXPR_SET_ELEM, assert() already validates this at the beginning of the loop. Remove redundant pointer to set element, use iterator index instead. Signed-off-by: Pablo Neira Ayuso --- src/evaluate.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/evaluate.c b/src/evaluate.c index 85c446a124ee..82736bc5211c 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2056,7 +2056,6 @@ static void expr_evaluate_set_ref(struct eval_ctx *ctx, struct expr *expr) static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) { struct expr *set = *expr, *i, *next; - const struct expr *elem; list_for_each_entry_safe(i, next, &expr_set(set)->expressions, list) { assert(i->etype == EXPR_SET_ELEM); @@ -2083,10 +2082,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) continue; } - elem = i; - - if (elem->etype == EXPR_SET_ELEM && - elem->key->etype == EXPR_SET_REF) + if (i->key->etype == EXPR_SET_REF) return expr_error(ctx->msgs, i, "Set reference cannot be part of another set"); @@ -2094,8 +2090,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) return expr_error(ctx->msgs, i, "Set member is not constant"); - if (i->etype == EXPR_SET_ELEM && - i->key->etype == EXPR_SET) { + if (i->key->etype == EXPR_SET) { /* Merge recursive set definitions */ list_splice_tail_init(&expr_set(i->key)->expressions, &i->list); list_del(&i->list); @@ -2104,9 +2099,9 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) expr_free(i); } else if (!expr_is_singleton(i)) { expr_set(set)->set_flags |= NFT_SET_INTERVAL; - if ((elem->key->etype == EXPR_MAPPING && - elem->key->left->etype == EXPR_CONCAT) || - elem->key->etype == EXPR_CONCAT) + if ((i->key->etype == EXPR_MAPPING && + i->key->left->etype == EXPR_CONCAT) || + i->key->etype == EXPR_CONCAT) expr_set(set)->set_flags |= NFT_SET_CONCAT; } } -- 2.30.2 --- src/segtree.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/segtree.c b/src/segtree.c index f95a7ce1c8a8..f9dddaa99176 100644 --- a/src/segtree.c +++ b/src/segtree.c @@ -53,8 +53,8 @@ static void interval_expr_copy(struct expr *dst, struct expr *src) list_splice_init(&src->stmt_list, &dst->stmt_list); } -static void set_elem_add(const struct set *set, struct expr *init, mpz_t value, - uint32_t flags, enum byteorder byteorder) +static void set_elem_expr_add(const struct set *set, struct expr *init, + mpz_t value, uint32_t flags, enum byteorder byteorder) { struct expr *expr; @@ -84,8 +84,8 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init) switch (i->key->etype) { case EXPR_VALUE: - set_elem_add(set, new_init, i->key->value, - i->flags, byteorder); + set_elem_expr_add(set, new_init, i->key->value, + i->flags, byteorder); break; case EXPR_CONCAT: set_expr_add(new_init, expr_clone(i)); @@ -97,11 +97,11 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init) break; default: range_expr_value_low(low, i); - set_elem_add(set, new_init, low, 0, i->byteorder); + set_elem_expr_add(set, new_init, low, 0, i->byteorder); range_expr_value_high(high, i); mpz_add_ui(high, high, 1); - set_elem_add(set, new_init, high, - EXPR_F_INTERVAL_END, i->byteorder); + set_elem_expr_add(set, new_init, high, + EXPR_F_INTERVAL_END, i->byteorder); break; } } -- 2.30.2 To prepare to replace EXPR_SET_ELEM by struct set_elem. Check that expr->flags for EXPR_SET_ELEM are zero from set_elem_expr_destroy() to validate this is correct. TODO: only EXPR_F_KERNEL in interval.c when converting to constant, prefix and range in __setelem_expr_to_range() ? --- src/evaluate.c | 13 +++++---- src/expression.c | 2 ++ src/intervals.c | 69 +++++++++++++++++++++++++----------------------- src/monitor.c | 2 +- src/netlink.c | 12 ++++----- src/segtree.c | 26 +++++++++--------- 6 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/evaluate.c b/src/evaluate.c index 82736bc5211c..63acac9e41cb 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1885,7 +1885,7 @@ static int __expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr *elem) struct stmt *set_stmt, *elem_stmt; if (num_set_exprs > 0 && num_elem_exprs != num_set_exprs) { - return expr_error(ctx->msgs, elem, + return expr_error(ctx->msgs, elem->key, "number of statements mismatch, set expects %d " "but element has %d", num_set_exprs, num_elem_exprs); @@ -1981,14 +1981,13 @@ static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr) } if (ctx->set && !elem_key_compatible(ctx->set->key, elem->key)) - return expr_error(ctx->msgs, elem, + return expr_error(ctx->msgs, elem->key, "Element mismatches %s definition, expected %s, not '%s'", set_is_map(ctx->set->flags) ? "map" : "set", ctx->set->key->dtype->desc, elem->key->dtype->desc); datatype_set(elem, elem->key->dtype); elem->len = elem->key->len; - elem->flags = elem->key->flags; return 0; @@ -2083,11 +2082,11 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) } if (i->key->etype == EXPR_SET_REF) - return expr_error(ctx->msgs, i, + return expr_error(ctx->msgs, i->key, "Set reference cannot be part of another set"); - if (!expr_is_constant(i)) - return expr_error(ctx->msgs, i, + if (!expr_is_constant(i->key)) + return expr_error(ctx->msgs, i->key, "Set member is not constant"); if (i->key->etype == EXPR_SET) { @@ -2097,7 +2096,7 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr) expr_set(set)->size += expr_set(i->key)->size - 1; expr_set(set)->set_flags |= expr_set(i->key)->set_flags; expr_free(i); - } else if (!expr_is_singleton(i)) { + } else if (!expr_is_singleton(i->key)) { expr_set(set)->set_flags |= NFT_SET_INTERVAL; if ((i->key->etype == EXPR_MAPPING && i->key->left->etype == EXPR_CONCAT) || diff --git a/src/expression.c b/src/expression.c index 68e2fec192b2..6321d3288dd9 100644 --- a/src/expression.c +++ b/src/expression.c @@ -1698,6 +1698,8 @@ static void set_elem_expr_destroy(struct expr *expr) { struct stmt *stmt, *next; + assert(expr->flags == 0); + free_const(expr->comment); expr_free(expr->key); list_for_each_entry_safe(stmt, next, &expr->stmt_list, list) diff --git a/src/intervals.c b/src/intervals.c index 3ac45cf29abd..e0943449c3db 100644 --- a/src/intervals.c +++ b/src/intervals.c @@ -31,6 +31,7 @@ static void __setelem_expr_to_range(struct expr **exprp) expr->len, expr->left->value, expr->right->value); + key->flags |= expr->flags & EXPR_F_KERNEL; expr_free(*exprp); *exprp = key; break; @@ -50,6 +51,7 @@ static void __setelem_expr_to_range(struct expr **exprp) expr->len, expr->prefix->value, rop); + key->flags |= expr->flags & EXPR_F_KERNEL; mpz_clear(rop); expr_free(*exprp); *exprp = key; @@ -64,6 +66,7 @@ static void __setelem_expr_to_range(struct expr **exprp) expr->len, expr->value, expr->value); + key->flags |= expr->flags & EXPR_F_KERNEL; expr_free(*exprp); *exprp = key; break; @@ -102,7 +105,7 @@ static void purge_elem(struct set_automerge_ctx *ctx, struct expr *i) static void remove_overlapping_range(struct set_automerge_ctx *ctx, struct expr *prev, struct expr *i) { - if (i->flags & EXPR_F_KERNEL) { + if (i->key->flags & EXPR_F_KERNEL) { i->location = prev->location; purge_elem(ctx, i); return; @@ -121,13 +124,13 @@ static bool merge_ranges(struct set_automerge_ctx *ctx, struct expr *prev, struct expr *i, struct range *prev_range, struct range *range) { - if (prev->flags & EXPR_F_KERNEL) { + if (prev->key->flags & EXPR_F_KERNEL) { prev->location = i->location; purge_elem(ctx, prev); mpz_set(i->key->range.low, prev->key->range.low); mpz_set(prev_range->high, range->high); return true; - } else if (i->flags & EXPR_F_KERNEL) { + } else if (i->key->flags & EXPR_F_KERNEL) { i->location = prev->location; purge_elem(ctx, i); mpz_set(prev->key->range.high, i->key->range.high); @@ -280,7 +283,7 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set, list_for_each_entry_safe(i, next, &expr_set(init)->expressions, list) { assert(i->etype == EXPR_SET_ELEM); - if (i->flags & EXPR_F_KERNEL) { + if (i->key->flags & EXPR_F_KERNEL) { list_move_tail(&i->list, &expr_set(existing_set->init)->expressions); } else if (existing_set) { if (debug_mask & NFT_DEBUG_SEGTREE) { @@ -288,7 +291,7 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set, i->key->range.low, i->key->range.high); } clone = expr_clone(i); - clone->flags |= EXPR_F_KERNEL; + clone->key->flags |= EXPR_F_KERNEL; __set_expr_add(existing_set->init, clone); } } @@ -310,7 +313,7 @@ static void remove_elem(struct expr *prev, struct set *set, struct expr *purge) { struct expr *clone; - if (prev->flags & EXPR_F_KERNEL) { + if (prev->key->flags & EXPR_F_KERNEL) { clone = expr_clone(prev); list_move_tail(&clone->list, &expr_set(purge)->expressions); } @@ -318,7 +321,7 @@ static void remove_elem(struct expr *prev, struct set *set, struct expr *purge) static void __adjust_elem_left(struct set *set, struct expr *prev, struct expr *i) { - prev->flags &= ~EXPR_F_KERNEL; + prev->key->flags &= ~EXPR_F_KERNEL; mpz_set(prev->key->range.low, i->key->range.high); mpz_add_ui(prev->key->range.low, prev->key->range.low, 1); list_move(&prev->list, &expr_set(set->existing_set->init)->expressions); @@ -337,7 +340,7 @@ static void adjust_elem_left(struct set *set, struct expr *prev, struct expr *i, static void __adjust_elem_right(struct set *set, struct expr *prev, struct expr *i) { - prev->flags &= ~EXPR_F_KERNEL; + prev->key->flags &= ~EXPR_F_KERNEL; mpz_set(prev->key->range.high, i->key->range.low); mpz_sub_ui(prev->key->range.high, prev->key->range.high, 1); list_move(&prev->list, &expr_set(set->existing_set->init)->expressions); @@ -361,12 +364,12 @@ static void split_range(struct set *set, struct expr *prev, struct expr *i, prev->location = i->location; - if (prev->flags & EXPR_F_KERNEL) { + if (prev->key->flags & EXPR_F_KERNEL) { clone = expr_clone(prev); list_move_tail(&clone->list, &expr_set(purge)->expressions); } - prev->flags &= ~EXPR_F_KERNEL; + prev->key->flags &= ~EXPR_F_KERNEL; clone = expr_clone(prev); mpz_set(clone->key->range.low, i->key->range.high); mpz_add_ui(clone->key->range.low, i->key->range.high, 1); @@ -386,15 +389,15 @@ static int setelem_adjust(struct set *set, struct expr *purge, { if (mpz_cmp(prev_range->low, range->low) == 0 && mpz_cmp(prev_range->high, range->high) > 0) { - if (i->flags & EXPR_F_REMOVE) + if (i->key->flags & EXPR_F_REMOVE) adjust_elem_left(set, prev, i, purge); } else if (mpz_cmp(prev_range->low, range->low) < 0 && mpz_cmp(prev_range->high, range->high) == 0) { - if (i->flags & EXPR_F_REMOVE) + if (i->key->flags & EXPR_F_REMOVE) adjust_elem_right(set, prev, i, purge); } else if (mpz_cmp(prev_range->low, range->low) < 0 && mpz_cmp(prev_range->high, range->high) > 0) { - if (i->flags & EXPR_F_REMOVE) + if (i->key->flags & EXPR_F_REMOVE) split_range(set, prev, i, purge); } else { return -1; @@ -440,13 +443,13 @@ static int setelem_delete(struct list_head *msgs, struct set *set, range_expr_value_high(range.high, i); } - if (!prev && elem->flags & EXPR_F_REMOVE) { + if (!prev && elem->key->flags & EXPR_F_REMOVE) { expr_error(msgs, i, "element does not exist"); err = -1; goto err; } - if (!(elem->flags & EXPR_F_REMOVE)) { + if (!(elem->key->flags & EXPR_F_REMOVE)) { prev = elem; mpz_set(prev_range.low, range.low); mpz_set(prev_range.high, range.high); @@ -455,8 +458,8 @@ static int setelem_delete(struct list_head *msgs, struct set *set, if (mpz_cmp(prev_range.low, range.low) == 0 && mpz_cmp(prev_range.high, range.high) == 0) { - if (elem->flags & EXPR_F_REMOVE) { - if (prev->flags & EXPR_F_KERNEL) { + if (elem->key->flags & EXPR_F_REMOVE) { + if (prev->key->flags & EXPR_F_KERNEL) { prev->location = elem->location; list_move_tail(&prev->list, &expr_set(purge)->expressions); } @@ -470,7 +473,7 @@ static int setelem_delete(struct list_head *msgs, struct set *set, err = -1; goto err; } - } else if (elem->flags & EXPR_F_REMOVE) { + } else if (elem->key->flags & EXPR_F_REMOVE) { expr_error(msgs, i, "element does not exist"); err = -1; goto err; @@ -506,7 +509,7 @@ static int __set_delete(struct list_head *msgs, struct expr *i, struct set *set, struct expr *init, struct set *existing_set, unsigned int debug_mask) { - i->flags |= EXPR_F_REMOVE; + i->key->flags |= EXPR_F_REMOVE; list_move_tail(&i->list, &expr_set(existing_set->init)->expressions); list_expr_sort(&expr_set(existing_set->init)->expressions); @@ -546,10 +549,10 @@ int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set, add = set_expr_alloc(&internal_location, set); list_for_each_entry(i, &expr_set(existing_set->init)->expressions, list) { - if (!(i->flags & EXPR_F_KERNEL)) { + if (!(i->key->flags & EXPR_F_KERNEL)) { clone = expr_clone(i); __set_expr_add(add, clone); - i->flags |= EXPR_F_KERNEL; + i->key->flags |= EXPR_F_KERNEL; } } @@ -616,9 +619,9 @@ static int setelem_overlap(struct list_head *msgs, struct set *set, if (mpz_cmp(prev_range.low, range.low) <= 0 && mpz_cmp(prev_range.high, range.high) >= 0) { - if (prev->flags & EXPR_F_KERNEL) + if (prev->key->flags & EXPR_F_KERNEL) expr_error(msgs, i, "interval overlaps with an existing one"); - else if (elem->flags & EXPR_F_KERNEL) + else if (elem->key->flags & EXPR_F_KERNEL) expr_error(msgs, prev, "interval overlaps with an existing one"); else expr_binary_error(msgs, i, prev, @@ -626,9 +629,9 @@ static int setelem_overlap(struct list_head *msgs, struct set *set, err = -1; goto err_out; } else if (mpz_cmp(range.low, prev_range.high) <= 0) { - if (prev->flags & EXPR_F_KERNEL) + if (prev->key->flags & EXPR_F_KERNEL) expr_error(msgs, i, "interval overlaps with an existing one"); - else if (elem->flags & EXPR_F_KERNEL) + else if (elem->key->flags & EXPR_F_KERNEL) expr_error(msgs, prev, "interval overlaps with an existing one"); else expr_binary_error(msgs, i, prev, @@ -666,11 +669,11 @@ int set_overlap(struct list_head *msgs, struct set *set, struct expr *init) list_for_each_entry_safe(i, n, &expr_set(init)->expressions, list) { assert(i->etype == EXPR_SET_ELEM); - if (i->flags & EXPR_F_KERNEL) + if (i->key->flags & EXPR_F_KERNEL) list_move_tail(&i->list, &expr_set(existing_set->init)->expressions); else if (existing_set) { clone = expr_clone(i); - clone->flags |= EXPR_F_KERNEL; + clone->key->flags |= EXPR_F_KERNEL; __set_expr_add(existing_set->init, clone); } } @@ -745,7 +748,7 @@ int set_to_intervals(const struct set *set, struct expr *init, bool add) root = set_elem_expr_alloc(&internal_location, expr); - root->flags |= EXPR_F_INTERVAL_END; + root->key->flags |= EXPR_F_INTERVAL_END; list_add(&root->list, &intervals); break; } @@ -821,7 +824,7 @@ int setelem_to_interval(const struct set *set, struct expr *elem, assert(!next_key || next_key->etype == EXPR_RANGE_VALUE); /* skip end element for adjacents intervals in anonymous sets. */ - if (!(elem->flags & EXPR_F_INTERVAL_END) && next_key) { + if (!(elem->key->flags & EXPR_F_INTERVAL_END) && next_key) { mpz_t p; mpz_init2(p, set->key->len); @@ -851,11 +854,11 @@ int setelem_to_interval(const struct set *set, struct expr *elem, if (adjacent) return 0; - else if (!mpz_cmp_ui(key->value, 0) && elem->flags & EXPR_F_INTERVAL_END) { - low->flags |= EXPR_F_INTERVAL_END; + else if (!mpz_cmp_ui(key->value, 0) && elem->key->flags & EXPR_F_INTERVAL_END) { + low->key->flags |= EXPR_F_INTERVAL_END; return 0; } else if (mpz_scan0(key->range.high, 0) == set->key->len) { - low->flags |= EXPR_F_INTERVAL_OPEN; + low->key->flags |= EXPR_F_INTERVAL_OPEN; return 0; } @@ -869,7 +872,7 @@ int setelem_to_interval(const struct set *set, struct expr *elem, high = set_elem_expr_alloc(&key->location, high); - high->flags |= EXPR_F_INTERVAL_END; + high->key->flags |= EXPR_F_INTERVAL_END; list_add_tail(&high->list, intervals); return 0; diff --git a/src/monitor.c b/src/monitor.c index e58f62252ca2..29d1360a5fe9 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -380,7 +380,7 @@ static bool set_elem_is_open_interval(struct expr *elem) { switch (elem->etype) { case EXPR_SET_ELEM: - return elem->flags & EXPR_F_INTERVAL_OPEN; + return elem->key->flags & EXPR_F_INTERVAL_OPEN; case EXPR_MAPPING: return set_elem_is_open_interval(elem->left); default: diff --git a/src/netlink.c b/src/netlink.c index 7a17f394c69f..7e4f77d24a3d 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -180,7 +180,7 @@ struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set, netlink_gen_stmt_stateful(stmt)); } } - if (elem->comment || expr->flags & EXPR_F_INTERVAL_OPEN) { + if (elem->comment || expr->key->flags & EXPR_F_INTERVAL_OPEN) { udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN); if (!udbuf) memory_allocation_error(); @@ -190,7 +190,7 @@ struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set, elem->comment)) memory_allocation_error(); } - if (expr->flags & EXPR_F_INTERVAL_OPEN) { + if (expr->key->flags & EXPR_F_INTERVAL_OPEN) { if (!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_ELEM_FLAGS, NFTNL_SET_ELEM_F_INTERVAL_OPEN)) memory_allocation_error(); @@ -232,7 +232,7 @@ struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set, nld.value, nld.len); } - if (expr->flags & EXPR_F_INTERVAL_END) + if (expr->key->flags & EXPR_F_INTERVAL_END) flags |= NFT_SET_ELEM_INTERVAL_END; if (key->etype == EXPR_SET_ELEM_CATCHALL) flags |= NFT_SET_ELEM_CATCHALL; @@ -1466,7 +1466,7 @@ static void set_elem_parse_udata(struct nftnl_set_elem *nlse, elem_flags = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_ELEM_FLAGS]); if (elem_flags & NFTNL_SET_ELEM_F_INTERVAL_OPEN) - expr->flags |= EXPR_F_INTERVAL_OPEN; + expr->key->flags |= EXPR_F_INTERVAL_OPEN; } } @@ -1563,7 +1563,7 @@ key_end: } out: expr = set_elem_expr_alloc(&netlink_location, key); - expr->flags |= EXPR_F_KERNEL; + expr->key->flags |= EXPR_F_KERNEL; if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT)) { expr->timeout = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_TIMEOUT); @@ -1592,7 +1592,7 @@ out: list_splice_tail_init(&setelem_parse_ctx.stmt_list, &expr->stmt_list); if (flags & NFT_SET_ELEM_INTERVAL_END) { - expr->flags |= EXPR_F_INTERVAL_END; + expr->key->flags |= EXPR_F_INTERVAL_END; if (mpz_cmp_ui(set->key->value, 0) == 0) set->root = true; } diff --git a/src/segtree.c b/src/segtree.c index f9dddaa99176..5dc4dba7035c 100644 --- a/src/segtree.c +++ b/src/segtree.c @@ -62,7 +62,7 @@ static void set_elem_expr_add(const struct set *set, struct expr *init, byteorder, set->key->len, NULL); mpz_set(expr->value, value); expr = set_elem_expr_alloc(&internal_location, expr); - expr->flags = flags; + expr->key->flags = flags; set_expr_add(init, expr); } @@ -85,11 +85,11 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init) switch (i->key->etype) { case EXPR_VALUE: set_elem_expr_add(set, new_init, i->key->value, - i->flags, byteorder); + i->key->flags, byteorder); break; case EXPR_CONCAT: set_expr_add(new_init, expr_clone(i)); - i->flags |= EXPR_F_INTERVAL_END; + i->key->flags |= EXPR_F_INTERVAL_END; set_expr_add(new_init, expr_clone(i)); break; case EXPR_SET_ELEM_CATCHALL: @@ -180,7 +180,7 @@ static struct expr *__expr_to_set_elem(struct expr *low, struct expr *expr) } elem = set_elem_expr_alloc(&low->location, expr); - elem->flags |= EXPR_F_KERNEL; + elem->key->flags |= EXPR_F_KERNEL; interval_expr_copy(elem, low); return elem; @@ -243,7 +243,7 @@ int get_set_decompose(struct set *cache_set, struct set *set) list_for_each_entry_safe(i, next, &expr_set(set->init)->expressions, list) { assert(i->etype == EXPR_SET_ELEM); - if (i->flags & EXPR_F_INTERVAL_END && left) { + if (i->key->flags & EXPR_F_INTERVAL_END && left) { list_del(&left->list); list_del(&i->list); mpz_sub_ui(i->key->value, i->key->value, 1); @@ -314,9 +314,9 @@ static int expr_value_cmp(const void *p1, const void *p2) ret = mpz_cmp(expr_value(e1)->value, expr_value(e2)->value); if (ret == 0) { - if (e1->flags & EXPR_F_INTERVAL_END) + if (e1->key->flags & EXPR_F_INTERVAL_END) return -1; - else if (e2->flags & EXPR_F_INTERVAL_END) + else if (e2->key->flags & EXPR_F_INTERVAL_END) return 1; } @@ -546,7 +546,7 @@ add_interval(struct expr *set, struct expr *low, struct expr *i) if (expr_basetype(low)->type == TYPE_STRING) mpz_switch_byteorder(expr_value(low)->value, expr_value(low)->len / BITS_PER_BYTE); - low->flags |= EXPR_F_KERNEL; + low->key->flags |= EXPR_F_KERNEL; expr = expr_get(low); } else if (range_is_prefix(range) && !mpz_cmp_ui(p, 0)) { @@ -601,11 +601,11 @@ void interval_map_decompose(struct expr *set) for (m = 0; m < size; m++) { i = elements[m]; - if (i->flags & EXPR_F_INTERVAL_END) + if (i->key->flags & EXPR_F_INTERVAL_END) interval = false; else if (interval) { end = expr_clone(i); - end->flags |= EXPR_F_INTERVAL_END; + end->key->flags |= EXPR_F_INTERVAL_END; ranges[n++] = end; } else interval = true; @@ -618,7 +618,7 @@ void interval_map_decompose(struct expr *set) i = ranges[n]; if (low == NULL) { - if (i->flags & EXPR_F_INTERVAL_END) { + if (i->key->flags & EXPR_F_INTERVAL_END) { /* * End of interval mark */ @@ -635,7 +635,7 @@ void interval_map_decompose(struct expr *set) add_interval(set, low, i); - if (i->flags & EXPR_F_INTERVAL_END) { + if (i->key->flags & EXPR_F_INTERVAL_END) { expr_free(low); low = NULL; } @@ -660,7 +660,7 @@ void interval_map_decompose(struct expr *set) out: if (catchall) { - catchall->flags |= EXPR_F_KERNEL; + catchall->key->flags |= EXPR_F_KERNEL; set_expr_add(set, catchall); } -- 2.30.2