"typeof ip saddr . ipsec in reqid" won't work because reqid uses integer type, i.e. dtype->size is 0. With "typeof", the size can be derived from the expression length, via set->key. This computes the concat length based either on dtype->size or expression length. It also updates concat evaluation to permit a zero datatype size if the subkey expression has nonzero length (i.e., typeof was used). Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- src/evaluate.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/evaluate.c b/src/evaluate.c index 503b4f036655..b5f74d2f5051 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1270,7 +1270,8 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr) } list_for_each_entry_safe(i, next, &(*expr)->expressions, list) { - unsigned dsize_bytes; + enum byteorder bo = BYTEORDER_INVALID; + unsigned dsize_bytes, dsize = 0; if (i->etype == EXPR_CT && (i->ct.key == NFT_CT_SRC || @@ -1286,14 +1287,18 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr) if (key) { tmp = key->dtype; + dsize = key->len; + bo = key->byteorder; off--; } else if (dtype == NULL) { tmp = datatype_lookup(TYPE_INVALID); } else { tmp = concat_subtype_lookup(type, --off); + dsize = tmp->size; + bo = tmp->byteorder; } - expr_set_context(&ctx->ectx, tmp, tmp->size); + __expr_set_context(&ctx->ectx, tmp, bo, dsize, 0); if (list_member_evaluate(ctx, &i) < 0) return -1; @@ -1315,12 +1320,14 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr) "data types (%s) in concat " "expressions", i->dtype->name); + if (dsize == 0) /* reload after evaluation or clone above */ + dsize = i->dtype->size; ntype = concat_subtype_add(ntype, i->dtype->type); - dsize_bytes = div_round_up(i->dtype->size, BITS_PER_BYTE); + dsize_bytes = div_round_up(dsize, BITS_PER_BYTE); (*expr)->field_len[(*expr)->field_count++] = dsize_bytes; - size += netlink_padded_len(i->dtype->size); + size += netlink_padded_len(dsize); if (key) key = list_next_entry(key, list); } @@ -4046,20 +4053,23 @@ static int set_expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr) i->dtype = dtype; } - if (i->dtype->size == 0) + if (i->dtype->size == 0 && i->len == 0) return expr_binary_error(ctx->msgs, i, *expr, "can not use variable sized " "data types (%s) in concat " "expressions", i->dtype->name); + if (i->dtype->size) + assert(i->len == i->dtype->size); + flags &= i->flags; ntype = concat_subtype_add(ntype, i->dtype->type); - dsize_bytes = div_round_up(i->dtype->size, BITS_PER_BYTE); + dsize_bytes = div_round_up(i->len, BITS_PER_BYTE); (*expr)->field_len[(*expr)->field_count++] = dsize_bytes; - size += netlink_padded_len(i->dtype->size); + size += netlink_padded_len(i->len); } (*expr)->flags |= flags; -- 2.35.1