summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/expression.h13
-rw-r--r--src/evaluate.c47
-rw-r--r--src/expression.c45
-rw-r--r--src/optimize.c3
-rw-r--r--src/parser_bison.y11
5 files changed, 116 insertions, 3 deletions
diff --git a/include/expression.h b/include/expression.h
index f2b45250..84727486 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -49,6 +49,7 @@
* @EXPR_SET_ELEM_CATCHALL catchall element expression
* @EXPR_FLAGCMP flagcmp expression
* @EXPR_RANGE_VALUE constant range expression
+ * @EXPR_RANGE_SYMBOL unparse symbol range expression
*/
enum expr_types {
EXPR_INVALID,
@@ -82,6 +83,7 @@ enum expr_types {
EXPR_SET_ELEM_CATCHALL,
EXPR_FLAGCMP,
EXPR_RANGE_VALUE,
+ EXPR_RANGE_SYMBOL,
EXPR_MAX = EXPR_FLAGCMP
};
@@ -261,9 +263,12 @@ struct expr {
union {
struct {
- /* EXPR_SYMBOL */
+ /* EXPR_SYMBOL, EXPR_RANGE_SYMBOL */
const struct scope *scope;
- const char *identifier;
+ union {
+ const char *identifier;
+ const char *identifier_range[2];
+ };
enum symbol_types symtype;
};
struct {
@@ -486,6 +491,10 @@ extern struct expr *constant_range_expr_alloc(const struct location *loc,
unsigned int len,
mpz_t low, mpz_t high);
+struct expr *symbol_range_expr_alloc(const struct location *loc,
+ enum symbol_types type, const struct scope *scope,
+ const char *identifier_low, const char *identifier_high);
+
extern struct expr *flag_expr_alloc(const struct location *loc,
const struct datatype *dtype,
enum byteorder byteorder,
diff --git a/src/evaluate.c b/src/evaluate.c
index 69240188..3cf58d85 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2319,6 +2319,51 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
return 0;
}
+static int expr_evaluate_symbol_range(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *left, *right, *range;
+ struct expr *expr = *exprp;
+
+ left = symbol_expr_alloc(&expr->location, expr->symtype, (struct scope *)expr->scope, expr->identifier_range[0]);
+ if (expr_evaluate_symbol(ctx, &left) < 0) {
+ expr_free(left);
+ return -1;
+ }
+
+ right = symbol_expr_alloc(&expr->location, expr->symtype, (struct scope *)expr->scope, expr->identifier_range[1]);
+ if (expr_evaluate_symbol(ctx, &right) < 0) {
+ expr_free(left);
+ expr_free(right);
+ return -1;
+ }
+
+ /* concatenation and maps need more work to use constant_range_expr. */
+ if (ctx->set && !set_is_map(ctx->set->flags) &&
+ set_is_non_concat_range(ctx->set) &&
+ left->etype == EXPR_VALUE &&
+ right->etype == EXPR_VALUE) {
+ range = constant_range_expr_alloc(&expr->location, left->dtype,
+ left->byteorder,
+ left->len,
+ left->value,
+ right->value);
+ expr_free(left);
+ expr_free(right);
+ expr_free(expr);
+ *exprp = range;
+ return 0;
+ }
+
+ range = range_expr_alloc(&expr->location, left, right);
+ expr_free(expr);
+ *exprp = range;
+
+ if (expr_evaluate(ctx, exprp) < 0)
+ return -1;
+
+ return 0;
+}
+
/* We got datatype context via statement. If the basetype is compatible, set
* this expression datatype to the one of the statement to make it datatype
* compatible. This is a more conservative approach than enabling datatype
@@ -3027,6 +3072,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
return expr_evaluate_set_elem_catchall(ctx, expr);
case EXPR_FLAGCMP:
return expr_evaluate_flagcmp(ctx, expr);
+ case EXPR_RANGE_SYMBOL:
+ return expr_evaluate_symbol_range(ctx, expr);
default:
BUG("unknown expression type %s\n", expr_name(*expr));
}
diff --git a/src/expression.c b/src/expression.c
index b98b3d96..53d4c521 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -620,6 +620,50 @@ struct expr *constant_range_expr_alloc(const struct location *loc,
return expr;
}
+static void symbol_range_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ nft_print(octx, "%s", expr->identifier_range[0]);
+ nft_print(octx, "-");
+ nft_print(octx, "%s", expr->identifier_range[1]);
+}
+
+static void symbol_range_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->symtype = expr->symtype;
+ new->scope = expr->scope;
+ new->identifier_range[0] = xstrdup(expr->identifier_range[0]);
+ new->identifier_range[1] = xstrdup(expr->identifier_range[1]);
+}
+
+static void symbol_range_expr_destroy(struct expr *expr)
+{
+ free_const(expr->identifier_range[0]);
+ free_const(expr->identifier_range[1]);
+}
+
+static const struct expr_ops symbol_range_expr_ops = {
+ .type = EXPR_RANGE_SYMBOL,
+ .name = "range_symbol",
+ .print = symbol_range_expr_print,
+ .clone = symbol_range_expr_clone,
+ .destroy = symbol_range_expr_destroy,
+};
+
+struct expr *symbol_range_expr_alloc(const struct location *loc,
+ enum symbol_types type, const struct scope *scope,
+ const char *identifier_low, const char *identifier_high)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_RANGE_SYMBOL, &invalid_type,
+ BYTEORDER_INVALID, 0);
+ expr->symtype = type;
+ expr->scope = scope;
+ expr->identifier_range[0] = xstrdup(identifier_low);
+ expr->identifier_range[1] = xstrdup(identifier_high);
+ return expr;
+}
+
/*
* Allocate a constant expression with a single bit set at position n.
*/
@@ -1699,6 +1743,7 @@ static const struct expr_ops *__expr_ops_by_type(enum expr_types etype)
case EXPR_SET_ELEM_CATCHALL: return &set_elem_catchall_expr_ops;
case EXPR_FLAGCMP: return &flagcmp_expr_ops;
case EXPR_RANGE_VALUE: return &constant_range_expr_ops;
+ case EXPR_RANGE_SYMBOL: return &symbol_range_expr_ops;
}
return NULL;
diff --git a/src/optimize.c b/src/optimize.c
index 03c8bad2..230fe4a2 100644
--- a/src/optimize.c
+++ b/src/optimize.c
@@ -139,6 +139,7 @@ static bool stmt_expr_supported(const struct expr *expr)
{
switch (expr->right->etype) {
case EXPR_SYMBOL:
+ case EXPR_RANGE_SYMBOL:
case EXPR_RANGE:
case EXPR_PREFIX:
case EXPR_SET:
@@ -630,6 +631,7 @@ static void __merge_concat(const struct optimize_ctx *ctx, uint32_t i,
case EXPR_SYMBOL:
case EXPR_VALUE:
case EXPR_PREFIX:
+ case EXPR_RANGE_SYMBOL:
case EXPR_RANGE:
clone = expr_clone(stmt_a->expr->right);
compound_expr_add(concat, clone);
@@ -730,6 +732,7 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict,
stmt_free(counter);
break;
case EXPR_PREFIX:
+ case EXPR_RANGE_SYMBOL:
case EXPR_RANGE:
case EXPR_VALUE:
case EXPR_SYMBOL:
diff --git a/src/parser_bison.y b/src/parser_bison.y
index fa8dc83f..f5512783 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -4425,7 +4425,16 @@ prefix_rhs_expr : basic_rhs_expr SLASH NUM
range_rhs_expr : basic_rhs_expr DASH basic_rhs_expr
{
- $$ = range_expr_alloc(&@$, $1, $3);
+ if ($1->etype == EXPR_SYMBOL &&
+ $1->symtype == SYMBOL_VALUE &&
+ $3->etype == EXPR_SYMBOL &&
+ $3->symtype == SYMBOL_VALUE) {
+ $$ = symbol_range_expr_alloc(&@$, $1->symtype, $1->scope, $1->identifier, $3->identifier);
+ expr_free($1);
+ expr_free($3);
+ } else {
+ $$ = range_expr_alloc(&@$, $1, $3);
+ }
}
;