From 3b20f47277c0cb4ea07ad30f94496c9f383035e7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 3 Mar 2018 22:52:35 +0100 Subject: src: add variable expression and use it to allow redefinitions Add new variable expression that we can use to attach symbols in runtime, this allows us to redefine variables via new keyword, eg. table ip x { chain y { define address = { 1.1.1.1, 2.2.2.2 } ip saddr $address redefine address = { 3.3.3.3 } ip saddr $address } } # nft list ruleset table ip x { chain y { ip saddr { 1.1.1.1, 2.2.2.2 } ip saddr { 3.3.3.3 } } } Note that redefinition just places a new symbol version before the existing one, so symbol lookups always find the latest version. The undefine keyword decrements the reference counter and removes the symbol from the list, so it cannot be used anymore. Still, previous references to this symbol via variable expression are still valid. Signed-off-by: Pablo Neira Ayuso --- src/rule.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'src/rule.c') 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; } -- cgit v1.2.3