From f86c86b7913f55c1221d8c5e1ff27700aa663a6e Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 13 Jun 2023 09:39:29 +0200 Subject: [PATCH] Filter/Conf: Method names have their own keyword hash To allow for future dynamic method definition, parsing method names is done via a dedicated keyword hash/scope. --- conf/cf-lex.l | 10 ++++++---- conf/conf.h | 6 ++++++ conf/confbase.Y | 2 +- conf/gen_keywords.m4 | 7 ++++--- conf/gen_parser.m4 | 2 ++ filter/config.Y | 29 +++++++++++++++++++++-------- 6 files changed, 40 insertions(+), 16 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 8dc0ac89..9e52417a 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -54,6 +54,7 @@ struct keyword { byte *name; int value; + enum keyword_scope scope; }; #include "conf/keywords.h" @@ -707,16 +708,17 @@ cf_lex_init(int is_cli, struct config *c) { global_root_scope_pool = rp_new(&root_pool, "Keywords pool"); linpool *kwlp = lp_new(global_root_scope_pool); - global_root_scope = lp_allocz(kwlp, sizeof(*global_root_scope)); + global_root_scope = lp_allocz(kwlp, sizeof(*global_root_scope) * CFK__MAX); for (const struct keyword *k = keyword_list; k->name; k++) { - struct symbol *sym = cf_new_symbol(global_root_scope, global_root_scope_pool, kwlp, k->name); + struct symbol *sym = cf_new_symbol(&global_root_scope[k->scope], global_root_scope_pool, kwlp, k->name); sym->class = SYM_KEYWORD; sym->keyword = k; } - global_root_scope->readonly = 1; + for (int s = 0; s < CFK__MAX; s++) + global_root_scope[s].readonly = 1; } ifs_head = ifs = push_ifs(NULL); @@ -740,7 +742,7 @@ cf_lex_init(int is_cli, struct config *c) if (is_cli) c->current_scope->next = config->root_scope; else - c->current_scope->next = global_root_scope; + c->current_scope->next = &global_root_scope[CFK_KEYWORDS]; } /** diff --git a/conf/conf.h b/conf/conf.h index 8558fcba..f91d7039 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -143,6 +143,12 @@ struct sym_scope { byte readonly:1; /* Do not add new symbols */ }; +enum keyword_scope { + CFK_KEYWORDS, + CFK_METHODS, + CFK__MAX +}; + extern struct sym_scope *global_root_scope; struct bytestring { diff --git a/conf/confbase.Y b/conf/confbase.Y index df1e038b..e10666f8 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -133,7 +133,7 @@ CF_DECLS %start config -CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM) +CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM, MAX, AS) CF_GRAMMAR diff --git a/conf/gen_keywords.m4 b/conf/gen_keywords.m4 index 4e8651f6..06a38ffd 100644 --- a/conf/gen_keywords.m4 +++ b/conf/gen_keywords.m4 @@ -23,10 +23,11 @@ m4_define(CF_DECLS, `m4_divert(-1)') m4_define(CF_DEFINES, `m4_divert(-1)') # Keywords are translated to C initializers -m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1 }, +m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1, CF_keywd_target }, m4_divert(-1)') -m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_handle_kw($1)]])') -m4_define(CF_KEYWORDS, `CF_iterate([[CF_keywd]], [[$@]])DNL') +m4_define(CF_keywd, `m4_ifdef([[CF_tok_]]CF_keywd_target[[_$1]],,[[m4_define([[CF_tok_]]CF_keywd_target[[_$1]],1)CF_handle_kw($1)]])') +m4_define(CF_KEYWORDS, `m4_define([[CF_keywd_target]],CFK_KEYWORDS)CF_iterate([[CF_keywd]], [[$@]])DNL') +m4_define(CF_METHODS, `m4_define([[CF_keywd_target]],CFK_METHODS)CF_iterate([[CF_keywd]], [[$@]])DNL') m4_define(CF_KEYWORDS_EXCLUSIVE, `CF_KEYWORDS($@)') # CLI commands generate keywords as well diff --git a/conf/gen_parser.m4 b/conf/gen_parser.m4 index caf22307..80071aef 100644 --- a/conf/gen_parser.m4 +++ b/conf/gen_parser.m4 @@ -35,6 +35,8 @@ m4_define(CF_append, `m4_define([[$1]], m4_ifdef([[$1]], m4_defn([[$1]])[[$3]])[ m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_append([[CF_kw_rule]],$1,[[ | ]])m4_define([[CF_toks]],CF_toks $1)]])') m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks )DNL') +m4_define(CF_METHODS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks +)DNL') m4_define(CF_keywd2, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)m4_define([[CF_toks]],CF_toks $1)]])') m4_define(CF_KEYWORDS_EXCLUSIVE, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd2]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks diff --git a/filter/config.Y b/filter/config.Y index e1eca9a5..b72e5ea7 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -21,6 +21,7 @@ static inline u32 pair_b(u32 p) { return p & 0xFFFF; } static struct f_method_scope { struct f_inst *object; + struct sym_scope scope; } f_method_scope_stack[32]; static int f_method_scope_pos = -1; @@ -32,12 +33,24 @@ static inline void f_push_method_scope(struct f_inst *object) cf_error("Too many nested method calls"); FM = (struct f_method_scope) { .object = object, + .scope = { + .next = new_config->current_scope, + .hash = global_root_scope[CFK_METHODS].hash, + .active = 1, + .block = 1, + .readonly = 1, + }, }; + new_config->current_scope = &FM.scope; } static inline void f_pop_method_scope(void) { ASSERT_DIE(f_method_scope_pos >= 0); + + ASSERT_DIE(&FM.scope == new_config->current_scope); + new_config->current_scope = FM.scope.next; + f_method_scope_pos--; } @@ -331,26 +344,26 @@ CF_DECLS CF_KEYWORDS_EXCLUSIVE(IN) CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, ACCEPT, REJECT, ERROR, - INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC, + INT, BOOL, IP, PREFIX, RD, PAIR, QUAD, EC, LC, SET, STRING, BYTESTRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST, IF, THEN, ELSE, CASE, FOR, DO, TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, - FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, ONLINK, + FROM, GW, NET, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, ONLINK, PREFERENCE, - ROA_CHECK, ASN, SRC, DST, - IS_V4, IS_V6, - LEN, MAXLEN, - DATA, DATA1, DATA2, + ROA_CHECK, DEFINED, ADD, DELETE, RESET, - PREPEND, FIRST, LAST, LAST_NONAGGREGATED, - MIN, MAX, + PREPEND, EMPTY, FILTER, WHERE, EVAL, ATTRIBUTE, FROM_HEX, BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT) +CF_METHODS(IS_V4, TYPE, IP, RD, LEN, MAXLEN, ASN, SRC, DST, MASK, + FIRST, LAST, LAST_NONAGGREGATED, DATA, DATA1, DATA2, MIN, MAX, + EMPTY, PREPEND, ADD, DELETE, FILTER) + %nonassoc THEN %nonassoc ELSE