diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 1b49b5a3..85f43c36 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -54,7 +54,6 @@ struct keyword { byte *name; int value; - struct keyword *next; }; #include "conf/keywords.h" @@ -67,16 +66,10 @@ struct keyword { static uint cf_hash(const byte *c); -#define KW_KEY(n) n->name -#define KW_NEXT(n) n->next -#define KW_EQ(a,b) !strcmp(a,b) -#define KW_FN(k) cf_hash(k) -#define KW_ORDER 8 /* Fixed */ - -#define SYM_KEY(n) n->name, n->scope->active +#define SYM_KEY(n) n->name #define SYM_NEXT(n) n->next -#define SYM_EQ(a,s1,b,s2) !strcmp(a,b) && s1 == s2 -#define SYM_FN(k,s) cf_hash(k) +#define SYM_EQ(a,b) !strcmp(a,b) +#define SYM_FN(k) cf_hash(k) #define SYM_ORDER 4 /* Initial */ #define SYM_REHASH sym_rehash @@ -85,14 +78,20 @@ static uint cf_hash(const byte *c); HASH_DEFINE_REHASH_FN(SYM, struct symbol) -HASH(struct keyword) kw_hash; -HASH(struct ea_class) ea_name_hash; +/* Global symbol scopes */ +static pool *global_root_scope_pool; +static struct sym_scope + global_root_scope = { + .active = 1, + }, + global_filter_scope = { + .active = 0, + .next = &global_root_scope, + }; +/* Local symbol scope: TODO this isn't thread-safe */ struct sym_scope *conf_this_scope; -static struct sym_scope global_root_scope__init = { .active = 1, }; -struct sym_scope *global_root_scope = &global_root_scope__init; - linpool *cfg_mem; int (*cf_read_hook)(byte *buf, unsigned int max, int fd); @@ -581,7 +580,7 @@ cf_new_symbol(const byte *c) s = cfg_allocz(sizeof(struct symbol) + l + 1); *s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, }; - strcpy(s->name, c); + memcpy(s->name, c, l+1); if (!conf_this_scope->hash.data) HASH_INIT(conf_this_scope->hash, new_config->pool, SYM_ORDER); @@ -595,20 +594,20 @@ cf_new_symbol(const byte *c) } static struct symbol * -cf_root_symbol(const byte *c) +cf_root_symbol(const byte *c, struct sym_scope *ss) { uint l = strlen(c); if (l > SYM_MAX_LEN) bug("Root symbol %s too long", c); struct symbol *s = mb_alloc(&root_pool, sizeof(struct symbol) + l + 1); - *s = (struct symbol) { .scope = global_root_scope, .class = SYM_VOID, }; + *s = (struct symbol) { .scope = ss, .class = SYM_VOID, }; memcpy(s->name, c, l+1); - if (!global_root_scope->hash.data) - HASH_INIT(global_root_scope->hash, &root_pool, SYM_ORDER); + if (!ss->hash.data) + HASH_INIT(ss->hash, &root_pool, SYM_ORDER); - HASH_INSERT2(global_root_scope->hash, SYM, &root_pool, s); + HASH_INSERT2(ss->hash, SYM, &root_pool, s); return s; } @@ -631,7 +630,7 @@ cf_find_symbol_scope(const struct sym_scope *scope, const byte *c) /* Find the symbol here or anywhere below */ while (scope) - if (scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c, 1))) + if (scope->active && scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c))) return s; else scope = scope->next; @@ -702,50 +701,34 @@ cf_lex_symbol(const char *data) struct symbol *sym = cf_get_symbol(data); cf_lval.s = sym; - /* Is it a keyword? Prefer the keyword. */ - struct keyword *k = HASH_FIND(kw_hash, KW, data); - if (k) + switch (sym->class) { - if (k->value > 0) - return k->value; - else - { - cf_lval.i = -k->value; - return ENUM; - } + case SYM_KEYWORD: + if (sym->keyword->value > 0) + return sym->keyword->value; + else + { + cf_lval.i = -sym->keyword->value; + return ENUM; + } + case SYM_VOID: + return CF_SYM_UNDEFINED; + default: + return CF_SYM_KNOWN; } - - /* OK, only a symbol. */ - if (sym->class == SYM_VOID) - return CF_SYM_UNDEFINED; - else - return CF_SYM_KNOWN; -} - -static void -cf_lex_init_kh(void) -{ - HASH_INIT(kw_hash, config_pool, KW_ORDER); - - struct keyword *k; - for (k=keyword_list; k->name; k++) - HASH_INSERT(kw_hash, KW, k); } void ea_lex_register(struct ea_class *def) { - struct symbol *sym = cf_root_symbol(def->name); - sym->class = SYM_ATTRIBUTE; - sym->attribute = def; - def->sym = sym; + def->sym = cf_define_symbol(cf_root_symbol(def->name, &global_filter_scope), SYM_ATTRIBUTE, attribute, def); } void ea_lex_unregister(struct ea_class *def) { struct symbol *sym = def->sym; - HASH_REMOVE2(global_root_scope->hash, SYM, &root_pool, sym); + HASH_REMOVE2(global_filter_scope.hash, SYM, &root_pool, sym); mb_free(sym); def->sym = NULL; } @@ -753,7 +736,11 @@ ea_lex_unregister(struct ea_class *def) struct ea_class * ea_class_find_by_name(const char *name) { - struct symbol *sym = cf_find_symbol(global_root_scope, name); + if (!global_filter_scope.hash.data) + return NULL; + + struct symbol *sym = HASH_FIND(global_filter_scope.hash, SYM, name); + if (!sym || (sym->class != SYM_ATTRIBUTE)) return NULL; else @@ -771,8 +758,13 @@ ea_class_find_by_name(const char *name) void cf_lex_init(int is_cli, struct config *c) { - if (!kw_hash.data) - cf_lex_init_kh(); + if (!global_root_scope_pool) + { + global_root_scope_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Keywords pool"); + + for (const struct keyword *k = keyword_list; k->name; k++) + cf_define_symbol(cf_root_symbol(k->name, &global_root_scope), SYM_KEYWORD, keyword, k); + } ifs_head = ifs = push_ifs(NULL); if (!is_cli) @@ -797,7 +789,7 @@ cf_lex_init(int is_cli, struct config *c) if (is_cli) conf_this_scope->next = config->root_scope; else - conf_this_scope->next = global_root_scope; + conf_this_scope->next = &global_filter_scope; } /** @@ -886,6 +878,27 @@ cf_swap_soft_scope(void) } } +/** + * cf_enter_filters - enable filter / route attributes namespace + */ +void +cf_enter_filters(void) +{ + ASSERT_DIE(!global_filter_scope.active); + global_filter_scope.active = 1; +} + +/** + * cf_exit_filters - disable filter / route attributes namespace + */ +void +cf_exit_filters(void) +{ + ASSERT_DIE(global_filter_scope.active); + global_filter_scope.active = 0; +} + + /** * cf_symbol_class_name - get name of a symbol class * @sym: symbol @@ -912,6 +925,8 @@ cf_symbol_class_name(struct symbol *sym) return "routing table"; case SYM_ATTRIBUTE: return "custom attribute"; + case SYM_KEYWORD: + return "symbol"; case SYM_CONSTANT_RANGE: return "constant"; case SYM_VARIABLE_RANGE: diff --git a/conf/conf.h b/conf/conf.h index 58a2733b..19663b3f 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -127,6 +127,7 @@ struct symbol { struct ea_class *attribute; /* For SYM_ATTRIBUTE */ struct f_val *val; /* For SYM_CONSTANT */ uint offset; /* For SYM_VARIABLE */ + const struct keyword *keyword; /* For SYM_KEYWORD */ }; char name[0]; @@ -144,7 +145,8 @@ struct sym_scope { byte soft_scopes; /* Number of soft scopes above */ }; -extern struct sym_scope *global_root_scope; +void cf_enter_filters(void); +void cf_exit_filters(void); struct bytestring { size_t length; @@ -161,6 +163,7 @@ struct bytestring { #define SYM_FILTER 4 #define SYM_TABLE 5 #define SYM_ATTRIBUTE 6 +#define SYM_KEYWORD 7 #define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */ #define SYM_VARIABLE_RANGE SYM_VARIABLE ... (SYM_VARIABLE | 0xff) diff --git a/conf/confbase.Y b/conf/confbase.Y index 40ea16de..c92d4810 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -121,7 +121,7 @@ CF_DECLS %type text opttext %type bytestring -%type symbol symbol_known toksym +%type symbol %type bytestring_text text_or_ipa %type bytestring_expr @@ -169,7 +169,7 @@ definition: expr: NUM | '(' term ')' { $$ = cf_eval_int($2); } - | symbol_known { + | CF_SYM_KNOWN { if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected"); $$ = SYM_VAL($1).i; } ; @@ -180,9 +180,7 @@ expr_us: | expr US { $$ = $1 US_; } ; -toksym: FROM | PREFERENCE ; -symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN | toksym ; -symbol_known: CF_SYM_KNOWN | toksym ; +symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN ; /* Switches */ diff --git a/conf/gen_keywords.m4 b/conf/gen_keywords.m4 index 53226e4d..5667ceaa 100644 --- a/conf/gen_keywords.m4 +++ b/conf/gen_keywords.m4 @@ -23,7 +23,7 @@ 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, NULL }, +m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1 }, 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') @@ -34,16 +34,16 @@ m4_define(CF_CLI, `CF_KEYWORDS(m4_translit($1, [[ ]], [[,]])) # Enums are translated to C initializers: use CF_ENUM(typename, prefix, values) # For different prefix: CF_ENUM_PX(typename, external prefix, C prefix, values) -m4_define(CF_enum, `m4_divert(1){ "CF_enum_prefix_ext[[]]$1", -((CF_enum_type<<16) | CF_enum_prefix_int[[]]$1), NULL }, +m4_define(CF_enum, `m4_divert(1){ "CF_enum_prefix_ext[[]]$1", -((CF_enum_type<<16) | CF_enum_prefix_int[[]]$1) }, m4_divert(-1)') m4_define(CF_ENUM, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix_ext]],$2)m4_define([[CF_enum_prefix_int]],$2)CF_iterate([[CF_enum]], [[m4_shift(m4_shift($@))]])DNL') m4_define(CF_ENUM_PX, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix_ext]],$2)m4_define([[CF_enum_prefix_int]],$3)CF_iterate([[CF_enum]], [[m4_shift(m4_shift(m4_shift($@)))]])DNL') -# After all configuration templates end, we generate the +# After all configuration templates end, we generate the keyword list m4_m4wrap(` m4_divert(0) -static struct keyword keyword_list[] = { -m4_undivert(1){ NULL, -1, NULL } }; +static const struct keyword keyword_list[] = { +m4_undivert(1){ NULL, -1 } }; ') # As we are processing C source, we must access all M4 primitives via diff --git a/filter/config.Y b/filter/config.Y index 194e312d..671ccb9d 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -364,13 +364,17 @@ conf: FILTER STACKS expr expr ';' { conf: filter_def ; filter_def: - FILTER symbol { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); } - filter_body { + FILTER symbol { + $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); + cf_enter_filters(); + cf_push_scope( $2 ); + } filter_body { struct filter *f = cfg_alloc(sizeof(struct filter)); *f = (struct filter) { .sym = $2, .root = $4 }; $2->filter = f; cf_pop_scope(); + cf_exit_filters(); } ; @@ -393,7 +397,7 @@ custom_attr: ATTRIBUTE type symbol ';' { conf: bt_test_suite ; bt_test_suite: - BT_TEST_SUITE '(' symbol_known ',' text ')' { + BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' { cf_assert_symbol($3, SYM_FUNCTION); struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); t->fn = $3->function; @@ -406,7 +410,7 @@ bt_test_suite: conf: bt_test_same ; bt_test_same: - BT_TEST_SAME '(' symbol_known ',' symbol_known ',' NUM ')' { + BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' { cf_assert_symbol($3, SYM_FUNCTION); cf_assert_symbol($5, SYM_FUNCTION); struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); @@ -488,23 +492,30 @@ function_vars: filter_body: function_body ; filter: - symbol_known { + CF_SYM_KNOWN { cf_assert_symbol($1, SYM_FILTER); $$ = $1->filter; } - | { cf_push_scope(NULL); } filter_body { + | { + cf_enter_filters(); + cf_push_scope(NULL); + } filter_body { struct filter *f = cfg_alloc(sizeof(struct filter)); *f = (struct filter) { .root = $2 }; $$ = f; cf_pop_scope(); + cf_exit_filters(); } ; where_filter: - WHERE term { + WHERE { + cf_enter_filters(); + } term { /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */ - $$ = f_new_where($2); + $$ = f_new_where($3); + cf_exit_filters(); } ; @@ -520,6 +531,7 @@ function_def: FUNCTION symbol { DBG( "Beginning of function %s\n", $2->name ); $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL); + cf_enter_filters(); cf_push_scope($2); } function_args { /* Make dummy f_line for storing function prototype */ @@ -540,6 +552,7 @@ function_def: $6->arg_list = $2->function->arg_list; $2->function = $6; cf_pop_scope(); + cf_exit_filters(); } ; @@ -601,7 +614,7 @@ set_atom: $$ = cf_eval_tmp($2, T_VOID); if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); } - | symbol_known { + | CF_SYM_KNOWN { cf_assert_symbol($1, SYM_CONSTANT); if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name); $$ = *$1->val; @@ -773,7 +786,7 @@ var_list: /* EMPTY */ { $$ = NULL; } | var_list ',' term { $$ = $3; $$->next = $1; } function_call: - symbol_known '(' var_list ')' + CF_SYM_KNOWN '(' var_list ')' { if ($1->class != SYM_FUNCTION) cf_error("You can't call something which is not a function. Really."); @@ -792,7 +805,7 @@ function_call: } ; -symbol_value: symbol_known +symbol_value: CF_SYM_KNOWN { switch ($1->class) { case SYM_CONSTANT_RANGE: @@ -951,7 +964,7 @@ cmd: $$ = f_new_inst(FI_FOR_INIT, $6, $3); $$->next = f_new_inst(FI_FOR_NEXT, $3, $9); } - | symbol_known '=' term ';' { + | CF_SYM_KNOWN '=' term ';' { switch ($1->class) { case SYM_VARIABLE_RANGE: $$ = f_new_inst(FI_VAR_SET, $3, $1); @@ -974,7 +987,7 @@ cmd: cf_error( "This static attribute is read-only."); $$ = f_new_inst(FI_RTA_SET, $3, $1); } - | UNSET '(' symbol_known ')' ';' { + | UNSET '(' CF_SYM_KNOWN ')' ';' { if ($3->class != SYM_ATTRIBUTE) cf_error("Can't unset %s", $3->name); if ($3->attribute->readonly) @@ -1004,11 +1017,11 @@ cmd: $$ = f_new_inst(FI_SWITCH, $2, $4); } - | symbol_known '.' EMPTY ';' { $$ = f_generate_empty($1); } - | symbol_known '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex_sym( FI_PATH_PREPEND, $1, $5 ); } - | symbol_known '.' ADD '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_ADD, $1, $5 ); } - | symbol_known '.' DELETE '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_DEL, $1, $5 ); } - | symbol_known '.' FILTER '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_FILTER, $1, $5 ); } + | CF_SYM_KNOWN '.' EMPTY ';' { $$ = f_generate_empty($1); } + | CF_SYM_KNOWN '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex_sym( FI_PATH_PREPEND, $1, $5 ); } + | CF_SYM_KNOWN '.' ADD '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_ADD, $1, $5 ); } + | CF_SYM_KNOWN '.' DELETE '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_DEL, $1, $5 ); } + | CF_SYM_KNOWN '.' FILTER '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_FILTER, $1, $5 ); } | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); } | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); } ; @@ -1019,7 +1032,7 @@ get_cf_position: }; lvalue: - symbol_known { + CF_SYM_KNOWN { switch ($1->class) { case SYM_VARIABLE_RANGE: $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; diff --git a/nest/config.Y b/nest/config.Y index e186c851..38594f33 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -154,8 +154,6 @@ CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6) CF_GRAMMAR -toksym: MIN | MAX ; - /* Setting of router ID */ conf: rtrid ; @@ -694,7 +692,7 @@ r_args: $$->addr = $3; $$->addr_mode = TE_ADDR_IN; } -| r_args TABLE symbol_known { +| r_args TABLE CF_SYM_KNOWN { cf_assert_symbol($3, SYM_TABLE); if (!$3->table) cf_error("Table %s not configured", $3->name); $$ = $1; @@ -741,7 +739,7 @@ r_args: $$ = $1; $$->filtered = 1; } - | r_args export_mode symbol_known { + | r_args export_mode CF_SYM_KNOWN { cf_assert_symbol($3, SYM_PROTO); struct proto_config *c = (struct proto_config *) $3->proto; $$ = $1; @@ -758,7 +756,7 @@ r_args: $$->export_channel = $3; $$->tables_defined_by = RSD_TDB_INDIRECT; } - | r_args PROTOCOL symbol_known { + | r_args PROTOCOL CF_SYM_KNOWN { cf_assert_symbol($3, SYM_PROTO); struct proto_config *c = (struct proto_config *) $3->proto; $$ = $1; @@ -870,7 +868,7 @@ sym_args: | sym_args FILTER { $$ = $1; $$->type = SYM_FILTER; } | sym_args PROTOCOL { $$ = $1; $$->type = SYM_PROTO; } | sym_args TEMPLATE { $$ = $1; $$->type = SYM_TEMPLATE; } - | sym_args symbol { $$ = $1; $$->sym = $2; } + | sym_args CF_SYM_KNOWN { $$ = $1; $$->sym = $2; } ; diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index a37bb27a..eef37f04 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -44,10 +44,6 @@ CF_KEYWORDS(CEASE, PREFIX, LIMIT, HIT, ADMINISTRATIVE, SHUTDOWN, RESET, PEER, CF_GRAMMAR -/* Workaround for collisions between keywords and symbols */ -toksym: ROLE | PEER | PROVIDER | CUSTOMER | RS_SERVER | RS_CLIENT ; -toksym: BGP_MED | BGP_LOCAL_PREF | SOURCE ; - proto: bgp_proto '}' ; bgp_proto_start: proto_start BGP { diff --git a/proto/static/config.Y b/proto/static/config.Y index 9d26ee82..f4b31f3f 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -153,7 +153,7 @@ stat_route_opts: stat_route_opt_list: /* empty */ - | '{' stat_route_opts '}' + | '{' { cf_enter_filters(); } stat_route_opts '}' { cf_exit_filters(); } ;