summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/expression.h10
-rw-r--r--include/rule.h5
-rw-r--r--src/evaluate.c21
-rw-r--r--src/expression.c39
-rw-r--r--src/parser_bison.y9
-rw-r--r--src/rule.c39
6 files changed, 101 insertions, 22 deletions
diff --git a/include/expression.h b/include/expression.h
index 26182120..7b9b6229 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -16,6 +16,7 @@
* @EXPR_INVALID: uninitialized type, should not happen
* @EXPR_VERDICT: nftables verdict expression
* @EXPR_SYMBOL: unparsed symbol
+ * @EXPR_VARIABLE: variable
* @EXPR_VALUE: literal numeric or string expression
* @EXPR_PREFIX: prefixed expression
* @EXPR_RANGE: literal range
@@ -41,6 +42,7 @@ enum expr_types {
EXPR_INVALID,
EXPR_VERDICT,
EXPR_SYMBOL,
+ EXPR_VARIABLE,
EXPR_VALUE,
EXPR_PREFIX,
EXPR_RANGE,
@@ -97,7 +99,6 @@ extern const char *expr_op_symbols[];
enum symbol_types {
SYMBOL_VALUE,
- SYMBOL_DEFINE,
SYMBOL_SET,
};
@@ -226,6 +227,10 @@ struct expr {
enum symbol_types symtype;
};
struct {
+ /* EXPR_VARIABLE */
+ struct symbol *sym;
+ };
+ struct {
/* EXPR_VERDICT */
int verdict;
const char *chain;
@@ -387,6 +392,9 @@ static inline void symbol_expr_set_type(struct expr *expr,
expr->dtype = dtype;
}
+struct expr *variable_expr_alloc(const struct location *loc,
+ struct scope *scope, struct symbol *sym);
+
extern struct expr *constant_expr_alloc(const struct location *loc,
const struct datatype *dtype,
enum byteorder byteorder,
diff --git a/include/rule.h b/include/rule.h
index 531222ce..58c4aeef 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -73,18 +73,21 @@ extern void scope_release(const struct scope *scope);
* @list: scope symbol list node
* @identifier: identifier
* @expr: initializer
+ * @refcnt: reference counter
*/
struct symbol {
struct list_head list;
const char *identifier;
struct expr *expr;
+ int refcnt;
};
extern void symbol_bind(struct scope *scope, const char *identifier,
struct expr *expr);
-extern int symbol_unbind(struct scope *scope, const char *identifier);
+extern int symbol_unbind(const struct scope *scope, const char *identifier);
extern struct symbol *symbol_lookup(const struct scope *scope,
const char *identifier);
+struct symbol *symbol_get(const struct scope *scope, const char *identifier);
enum table_flags {
TABLE_F_DORMANT = (1 << 0),
diff --git a/src/evaluate.c b/src/evaluate.c
index 40a9292f..cc8eac83 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -168,7 +168,6 @@ static struct table *table_lookup_global(struct eval_ctx *ctx)
static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
{
struct error_record *erec;
- struct symbol *sym;
struct table *table;
struct set *set;
struct expr *new;
@@ -183,14 +182,6 @@ static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
return -1;
}
break;
- case SYMBOL_DEFINE:
- sym = symbol_lookup((*expr)->scope, (*expr)->identifier);
- if (sym == NULL)
- return expr_error(ctx->msgs, *expr,
- "undefined identifier '%s'",
- (*expr)->identifier);
- new = expr_clone(sym->expr);
- break;
case SYMBOL_SET:
ret = cache_update(ctx->nf_sock, ctx->cache, ctx->cmd->op,
ctx->msgs, ctx->debug_mask & NFT_DEBUG_NETLINK, ctx->octx);
@@ -1776,6 +1767,16 @@ static int expr_evaluate_meta(struct eval_ctx *ctx, struct expr **exprp)
return expr_evaluate_primary(ctx, exprp);
}
+static int expr_evaluate_variable(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *new = expr_clone((*exprp)->sym->expr);
+
+ expr_free(*exprp);
+ *exprp = new;
+
+ return expr_evaluate(ctx, exprp);
+}
+
static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
{
if (ctx->debug_mask & NFT_DEBUG_EVALUATION) {
@@ -1791,6 +1792,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
switch ((*expr)->ops->type) {
case EXPR_SYMBOL:
return expr_evaluate_symbol(ctx, expr);
+ case EXPR_VARIABLE:
+ return expr_evaluate_variable(ctx, expr);
case EXPR_SET_REF:
return 0;
case EXPR_VALUE:
diff --git a/src/expression.c b/src/expression.c
index 393c1b2b..ee75284e 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -254,6 +254,45 @@ struct expr *symbol_expr_alloc(const struct location *loc,
return expr;
}
+static void variable_expr_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ nft_print(octx, "$%s", expr->sym->identifier);
+}
+
+static void variable_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->scope = expr->scope;
+ new->sym = expr->sym;
+
+ expr->sym->refcnt++;
+}
+
+static void variable_expr_destroy(struct expr *expr)
+{
+ expr->sym->refcnt--;
+}
+
+static const struct expr_ops variable_expr_ops = {
+ .type = EXPR_VARIABLE,
+ .name = "variable",
+ .print = variable_expr_print,
+ .clone = variable_expr_clone,
+ .destroy = variable_expr_destroy,
+};
+
+struct expr *variable_expr_alloc(const struct location *loc,
+ struct scope *scope, struct symbol *sym)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, &variable_expr_ops, &invalid_type,
+ BYTEORDER_INVALID, 0);
+ expr->scope = scope;
+ expr->sym = sym;
+ return expr;
+}
+
static void constant_expr_print(const struct expr *expr,
struct output_ctx *octx)
{
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 58bc6805..ee6729f1 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -771,8 +771,6 @@ common_block : INCLUDE QUOTED_STRING stmt_separator
{
struct scope *scope = current_scope(state);
- /* ignore missing identifier */
- symbol_unbind(scope, $2);
symbol_bind(scope, $2, $4);
xfree($2);
}
@@ -2584,16 +2582,17 @@ match_stmt : relational_expr
variable_expr : '$' identifier
{
struct scope *scope = current_scope(state);
+ struct symbol *sym;
- if (symbol_lookup(scope, $2) == NULL) {
+ sym = symbol_get(scope, $2);
+ if (!sym) {
erec_queue(error(&@2, "unknown identifier '%s'", $2),
state->msgs);
xfree($2);
YYERROR;
}
- $$ = symbol_expr_alloc(&@$, SYMBOL_DEFINE,
- scope, $2);
+ $$ = variable_expr_alloc(&@$, scope, sym);
xfree($2);
}
;
diff --git a/src/rule.c b/src/rule.c
index c0b42b1c..b331416a 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -467,6 +467,7 @@ void scope_release(const struct scope *scope)
struct symbol *sym, *next;
list_for_each_entry_safe(sym, next, &scope->symbols, list) {
+ assert(sym->refcnt == 1);
list_del(&sym->list);
xfree(sym->identifier);
expr_free(sym->expr);
@@ -481,22 +482,48 @@ void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr)
sym = xzalloc(sizeof(*sym));
sym->identifier = xstrdup(identifier);
sym->expr = expr;
+ sym->refcnt = 1;
- list_add_tail(&sym->list, &scope->symbols);
+ list_add(&sym->list, &scope->symbols);
}
-int symbol_unbind(struct scope *scope, const char *identifier)
+struct symbol *symbol_get(const struct scope *scope, const char *identifier)
{
struct symbol *sym;
sym = symbol_lookup(scope, identifier);
if (!sym)
- return -1;
+ return NULL;
+
+ sym->refcnt++;
+ return sym;
+}
+
+static void symbol_put(struct symbol *sym)
+{
+ if (--sym->refcnt == 0) {
+ xfree(sym->identifier);
+ expr_free(sym->expr);
+ xfree(sym);
+ }
+}
+
+static void symbol_remove(struct symbol *sym)
+{
list_del(&sym->list);
- xfree(sym->identifier);
- expr_free(sym->expr);
- xfree(sym);
+ symbol_put(sym);
+}
+
+int symbol_unbind(const struct scope *scope, const char *identifier)
+{
+ struct symbol *sym, *next;
+
+ list_for_each_entry_safe(sym, next, &scope->symbols, list) {
+ if (!strcmp(sym->identifier, identifier))
+ symbol_remove(sym);
+ }
+
return 0;
}