From: Maria Matejka Date: Wed, 25 Oct 2023 12:41:11 +0000 (+0200) Subject: Merge commit '58efa944' into thread-next X-Git-Tag: v3.0.0~380 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=da52d661774a5637bc6ca63c018f542b40941e00;p=thirdparty%2Fbird.git Merge commit '58efa944' into thread-next Conflicts: conf/cf-lex.l conf/conf.h conf/confbase.Y conf/gen_keywords.m4 conf/gen_parser.m4 filter/config.Y nest/config.Y proto/bgp/config.Y proto/static/config.Y Keywords and attributes are split to separate namespaces, to avoid collisions between regular keyword use and attribute overlay. --- da52d661774a5637bc6ca63c018f542b40941e00 diff --cc conf/cf-lex.l index 1b49b5a3f,fb2ffb325..85f43c369 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@@ -85,14 -78,10 +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; - -struct sym_scope *conf_this_scope; -struct sym_scope *global_root_scope; ++/* 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); @@@ -579,14 -568,19 +578,14 @@@ cf_new_symbol(const byte *c cf_swap_soft_scope(); - pool *p = new_config->pool; - - if (conf_this_scope == global_root_scope) - s = mb_allocz(p = global_root_scope_pool, sizeof(struct symbol) + l + 1); - else - s = cfg_allocz(sizeof(struct symbol) + l + 1); + 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, p, SYM_ORDER); + HASH_INIT(conf_this_scope->hash, new_config->pool, SYM_ORDER); - HASH_INSERT2(conf_this_scope->hash, SYM, p, s); + HASH_INSERT2(conf_this_scope->hash, SYM, new_config->pool, s); if (conf_this_scope == new_config->root_scope) add_tail(&(new_config->symbols), &(s->n)); @@@ -594,24 -588,9 +593,24 @@@ return s; } -struct symbol * -cf_symbol_from_keyword(const struct keyword *kw) -{ return cf_new_symbol(kw->name); } +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; +} + /** * cf_find_symbol_scope - find a symbol by name @@@ -631,7 -610,7 +630,7 @@@ cf_find_symbol_scope(const struct sym_s /* Find the symbol here or anywhere below */ while (scope) - if (scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c, 1))) - if (scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c))) ++ if (scope->active && scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c))) return s; else scope = scope->next; @@@ -702,64 -681,22 +701,52 @@@ 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: - { - int val = sym->keyword->value; - if (val > 0) return val; - cf_lval.i = -val; - return ENUM; - } ++ 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; +} + +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 + return sym->attribute; +} + /** * cf_lex_init - initialize the lexer * @is_cli: true if we're going to parse CLI command, false for configuration @@@ -771,8 -708,14 +758,13 @@@ 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, "Keywords pool"); - conf_this_scope = global_root_scope = mb_allocz(global_root_scope_pool, sizeof(*global_root_scope)); ++ 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_get_symbol(k->name), SYM_KEYWORD, keyword, 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 -740,7 +789,7 @@@ 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 -829,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 -855,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 --cc conf/conf.h index 58a2733b6,12f1a6b39..19663b3f6 --- a/conf/conf.h +++ b/conf/conf.h @@@ -124,9 -120,10 +124,10 @@@ struct symbol const struct f_line *function; /* For SYM_FUNCTION */ const struct filter *filter; /* For SYM_FILTER */ struct rtable_config *table; /* For SYM_TABLE */ - struct f_dynamic_attr *attribute; /* For SYM_ATTRIBUTE */ + 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 -141,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; diff --cc conf/confbase.Y index 40ea16de3,0c2807dc5..c92d4810e --- a/conf/confbase.Y +++ b/conf/confbase.Y @@@ -121,7 -118,7 +121,7 @@@ CF_DECL %type text opttext %type bytestring - %type symbol symbol_known toksym -%type symbol symbol_known ++%type symbol %type bytestring_text text_or_ipa %type bytestring_expr @@@ -169,7 -166,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 -177,8 +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 | KEYWORD ; -symbol_known: CF_SYM_KNOWN | KEYWORD ; ++symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN ; /* Switches */ diff --cc conf/gen_keywords.m4 index 53226e4da,4e8651f6d..5667ceaaa --- a/conf/gen_keywords.m4 +++ b/conf/gen_keywords.m4 @@@ -39,11 -40,11 +39,11 @@@ 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 --cc filter/config.Y index 194e312db,fcdbb4a9d..671ccb9d8 --- a/filter/config.Y +++ b/filter/config.Y @@@ -356,21 -349,15 +356,25 @@@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UN CF_GRAMMAR +conf: FILTER STACKS expr expr ';' { + new_config->filter_vstk = $3; + new_config->filter_estk = $4; + } + ; + 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 -373,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 -386,7 +410,7 @@@ 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 -468,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 -500,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 -520,6 +552,7 @@@ $6->arg_list = $2->function->arg_list; $2->function = $6; cf_pop_scope(); ++ cf_exit_filters(); } ; @@@ -598,10 -578,10 +611,10 @@@ set_atom | VPN_RD { $$.type = T_RD; $$.val.ec = $1; } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | '(' term ')' { - $$ = cf_eval($2, T_VOID); + $$ = 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 -753,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 -772,7 +805,7 @@@ } ; - symbol_value: symbol_known -symbol_value: symbol_known ++symbol_value: CF_SYM_KNOWN { switch ($1->class) { case SYM_CONSTANT_RANGE: @@@ -951,7 -938,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,12 -962,8 +987,12 @@@ cf_error( "This static attribute is read-only."); $$ = f_new_inst(FI_RTA_SET, $3, $1); } - | UNSET '(' symbol_known ')' ';' { - | UNSET '(' dynamic_attr ')' ';' { - $$ = f_new_inst(FI_EA_UNSET, $3); ++ | UNSET '(' CF_SYM_KNOWN ')' ';' { + if ($3->class != SYM_ATTRIBUTE) + cf_error("Can't unset %s", $3->name); + if ($3->attribute->readonly) + cf_error("Attribute %s is read-only", $3->attribute->name); + $$ = f_new_inst(FI_EA_UNSET, $3->attribute); } | break_command print_list ';' { struct f_inst *breaker = f_new_inst(FI_DIE, $1); @@@ -1004,11 -988,11 +1017,11 @@@ $$ = 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 ); } - | dynamic_attr '.' EMPTY ';' { $$ = f_new_inst(FI_EA_SET, f_const_empty($1), $1); } - | dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); } - | dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); } - | dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); } - | dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( 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,17 -1003,8 +1032,17 @@@ get_cf_position }; lvalue: - symbol_known { - CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; } ++ CF_SYM_KNOWN { + switch ($1->class) { + case SYM_VARIABLE_RANGE: + $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; + break; + case SYM_ATTRIBUTE: + $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1->attribute }; + break; + } + } | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; } - | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; }; + ; CF_END diff --cc nest/config.Y index e186c8516,8aaf0128f..38594f339 --- a/nest/config.Y +++ b/nest/config.Y @@@ -692,11 -664,10 +690,11 @@@ r_args if ($$->addr) cf_error("Only one prefix expected"); if (!net_type_match($3, NB_IP)) cf_error("Only IP networks accepted for 'in' argument"); $$->addr = $3; - $$->addr_mode = RSD_ADDR_IN; + $$->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; rt_show_add_table($$, $3->table->table); $$->tables_defined_by = RSD_TDB_DIRECT; @@@ -741,7 -711,7 +739,7 @@@ $$ = $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 -728,7 +756,7 @@@ $$->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; diff --cc proto/static/config.Y index 9d26ee82b,9d26ee82b..f4b31f3f3 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@@ -153,7 -153,7 +153,7 @@@ stat_route_opts stat_route_opt_list: /* empty */ -- | '{' stat_route_opts '}' ++ | '{' { cf_enter_filters(); } stat_route_opts '}' { cf_exit_filters(); } ;