0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-09 20:58:44 +00:00

Merge commit '0a729b50' into thread-next

This merge was particularly difficult. I finally resorted to delete the
symbol scope active flag altogether and replace its usage by other
means.

Also I had to update custom route attribute registration to fit
both the scope updates in v2 and the data model in v3.
This commit is contained in:
Maria Matejka 2023-10-29 15:42:46 +01:00
commit c5f6dc8142
16 changed files with 95 additions and 58 deletions

View File

@ -78,10 +78,8 @@ pool *global_root_scope_pool;
linpool *global_root_scope_linpool; linpool *global_root_scope_linpool;
static struct sym_scope static struct sym_scope
global_root_scope = { global_root_scope = {
.active = 1,
}, },
global_filter_scope = { global_filter_scope = {
.active = 0,
.next = &global_root_scope, .next = &global_root_scope,
}; };
@ -634,7 +632,8 @@ cf_find_symbol_scope(const struct sym_scope *scope, const byte *c)
/* Find the symbol here or anywhere below */ /* Find the symbol here or anywhere below */
while (scope) while (scope)
if (scope->active && scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c))) if (((scope != &global_filter_scope) || !new_config || new_config->allow_attributes) &&
scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c)))
return s; return s;
else else
scope = scope->next; scope = scope->next;
@ -735,6 +734,8 @@ ea_lex_register(struct ea_class *def)
def->sym->attribute = def; def->sym->attribute = def;
} }
#if 0
/* When we start to support complete protocol removal, we may need this function */
void void
ea_lex_unregister(struct ea_class *def) ea_lex_unregister(struct ea_class *def)
{ {
@ -743,19 +744,13 @@ ea_lex_unregister(struct ea_class *def)
mb_free(sym); mb_free(sym);
def->sym = NULL; def->sym = NULL;
} }
#endif
struct ea_class * struct ea_class *
ea_class_find_by_name(const char *name) ea_class_find_by_name(const char *name)
{ {
if (!global_filter_scope.hash.data) struct symbol *sym = cf_find_symbol_scope(config ? config->root_scope : &global_filter_scope, name);
return NULL; return sym && (sym->class == SYM_ATTRIBUTE) ? sym->attribute : NULL;
struct symbol *sym = HASH_FIND(global_filter_scope.hash, SYM, name);
if (!sym || (sym->class != SYM_ATTRIBUTE))
return NULL;
else
return sym->attribute;
} }
void f_type_methods_register(void); void f_type_methods_register(void);
@ -803,7 +798,6 @@ cf_lex_init(int is_cli, struct config *c)
BEGIN(INITIAL); BEGIN(INITIAL);
c->root_scope = c->current_scope = cfg_allocz(sizeof(struct sym_scope)); c->root_scope = c->current_scope = cfg_allocz(sizeof(struct sym_scope));
c->root_scope->active = 1;
if (is_cli) if (is_cli)
c->current_scope->next = config->root_scope; c->current_scope->next = config->root_scope;
@ -828,7 +822,6 @@ cf_push_scope(struct config *conf, struct symbol *sym)
s->next = conf->current_scope; s->next = conf->current_scope;
conf->current_scope = s; conf->current_scope = s;
s->active = 1;
s->name = sym; s->name = sym;
s->slots = 0; s->slots = 0;
} }
@ -844,10 +837,7 @@ void
cf_pop_scope(struct config *conf) cf_pop_scope(struct config *conf)
{ {
ASSERT(!conf->current_scope->soft_scopes); ASSERT(!conf->current_scope->soft_scopes);
conf->current_scope->active = 0;
conf->current_scope = conf->current_scope->next; conf->current_scope = conf->current_scope->next;
ASSERT(conf->current_scope); ASSERT(conf->current_scope);
} }
@ -903,8 +893,8 @@ cf_swap_soft_scope(struct config *conf)
void void
cf_enter_filters(void) cf_enter_filters(void)
{ {
ASSERT_DIE(!global_filter_scope.active); ASSERT_DIE(!new_config->allow_attributes);
global_filter_scope.active = 1; new_config->allow_attributes = 1;
} }
/** /**
@ -913,8 +903,8 @@ cf_enter_filters(void)
void void
cf_exit_filters(void) cf_exit_filters(void)
{ {
ASSERT_DIE(global_filter_scope.active); ASSERT_DIE(new_config->allow_attributes);
global_filter_scope.active = 0; new_config->allow_attributes = 0;
} }

View File

@ -60,7 +60,8 @@
static jmp_buf conf_jmpbuf; static jmp_buf conf_jmpbuf;
struct config *config, *new_config; struct config *config;
_Thread_local struct config *new_config;
pool *config_pool; pool *config_pool;
static struct config *old_config; /* Old configuration */ static struct config *old_config; /* Old configuration */

View File

@ -58,6 +58,7 @@ struct config {
struct sym_scope *root_scope; /* Scope for root symbols */ struct sym_scope *root_scope; /* Scope for root symbols */
struct sym_scope *current_scope; /* Current scope where we are actually in while parsing */ struct sym_scope *current_scope; /* Current scope where we are actually in while parsing */
int allow_attributes; /* Allow attributes in the current state of configuration parsing */
_Atomic int obstacle_count; /* Number of items blocking freeing of this config */ _Atomic int obstacle_count; /* Number of items blocking freeing of this config */
event done_event; /* Called when obstacle_count reaches zero */ event done_event; /* Called when obstacle_count reaches zero */
int shutdown; /* This is a pseudo-config for daemon shutdown */ int shutdown; /* This is a pseudo-config for daemon shutdown */
@ -67,7 +68,7 @@ struct config {
/* Please don't use these variables in protocols. Use proto_config->global instead. */ /* Please don't use these variables in protocols. Use proto_config->global instead. */
extern struct config *config; /* Currently active configuration */ extern struct config *config; /* Currently active configuration */
extern struct config *new_config; /* Configuration being parsed */ extern _Thread_local struct config *new_config; /* Configuration being parsed */
struct config *config_alloc(const char *name); struct config *config_alloc(const char *name);
int config_parse(struct config *); int config_parse(struct config *);
@ -149,7 +150,6 @@ struct sym_scope {
uint slots; /* Variable slots */ uint slots; /* Variable slots */
byte soft_scopes; /* Number of soft scopes above */ byte soft_scopes; /* Number of soft scopes above */
byte active:1; /* Currently entered */
byte block:1; /* No independent stack frame */ byte block:1; /* No independent stack frame */
byte readonly:1; /* Do not add new symbols */ byte readonly:1; /* Do not add new symbols */
}; };

View File

@ -3313,6 +3313,13 @@ some of them (marked with `<tt/O/') are optional.
name="local Role"> is configured it set automatically. name="local Role"> is configured it set automatically.
</descrip> </descrip>
<p>For attributes unknown by BIRD, the user can assign a name (on top level)
to an attribute by its number. This defined name can be used then to both set
(by a bytestring literal, transitive) or unset the given attribute even though
BIRD knows nothing about it:
<tt><label id="bgp-attribute-custom">attribute bgp <m/number/ bytestring <m/name/;</tt>
<sect1>Example <sect1>Example
<label id="bgp-exam"> <label id="bgp-exam">

View File

@ -28,6 +28,8 @@ static struct f_method_scope {
} f_method_scope_stack[32]; } f_method_scope_stack[32];
static int f_method_scope_pos = -1; static int f_method_scope_pos = -1;
static struct sym_scope *f_for_stored_scope;
#define FM (f_method_scope_stack[f_method_scope_pos]) #define FM (f_method_scope_stack[f_method_scope_pos])
static inline void f_method_call_start(struct f_inst *object) static inline void f_method_call_start(struct f_inst *object)
@ -41,13 +43,14 @@ static inline void f_method_call_start(struct f_inst *object)
if (!scope) if (!scope)
cf_error("No methods defined for type %s", f_type_name(object->type)); cf_error("No methods defined for type %s", f_type_name(object->type));
/* Replacing the current symbol scope with the appropriate method scope
for the given type. */
FM = (struct f_method_scope) { FM = (struct f_method_scope) {
.object = object, .object = object,
.main = new_config->current_scope, .main = new_config->current_scope,
.scope = { .scope = {
.next = NULL, .next = NULL,
.hash = scope->hash, .hash = scope->hash,
.active = 1,
.block = 1, .block = 1,
.readonly = 1, .readonly = 1,
}, },
@ -57,22 +60,16 @@ static inline void f_method_call_start(struct f_inst *object)
static inline void f_method_call_args(void) static inline void f_method_call_args(void)
{ {
ASSERT_DIE(FM.scope.active); /* For argument parsing, we need to revert back to the standard symbol scope. */
FM.scope.active = 0;
new_config->current_scope = FM.main; new_config->current_scope = FM.main;
} }
static inline void f_method_call_end(void) static inline void f_method_call_end(void)
{ {
ASSERT_DIE(f_method_scope_pos >= 0); ASSERT_DIE(f_method_scope_pos >= 0);
if (FM.scope.active) { if (&FM.scope == new_config->current_scope)
ASSERT_DIE(&FM.scope == new_config->current_scope);
new_config->current_scope = FM.main; new_config->current_scope = FM.main;
FM.scope.active = 0;
}
f_method_scope_pos--; f_method_scope_pos--;
} }
@ -423,14 +420,18 @@ filter_eval:
conf: custom_attr ; conf: custom_attr ;
custom_attr: ATTRIBUTE type symbol ';' { custom_attr: ATTRIBUTE type symbol ';' {
if (($3->class == SYM_ATTRIBUTE) && ($3->scope == new_config->root_scope)) cf_enter_filters();
cf_error("Duplicate attribute %s definition", $3->name); struct ea_class *ac = ea_class_find_by_name($3->name);
cf_exit_filters();
cf_define_symbol(new_config, $3, SYM_ATTRIBUTE, attribute, if (ac && (ac->type == $2))
ea_register_alloc(new_config->pool, (struct ea_class) { ea_ref_class(new_config->pool, ac);
else
ac = ea_register_alloc(new_config->pool, (struct ea_class) {
.name = $3->name, .name = $3->name,
.type = $2, .type = $2,
})->class); })->class;
cf_define_symbol(new_config, $3, SYM_ATTRIBUTE, attribute, ac);
}; };
conf: bt_test_suite ; conf: bt_test_suite ;
@ -1003,7 +1004,15 @@ cmd:
new_config->current_scope->slots += 2; new_config->current_scope->slots += 2;
} for_var IN } for_var IN
/* Parse term in the parent scope */ /* Parse term in the parent scope */
{ new_config->current_scope->active = 0; } term { new_config->current_scope->active = 1; } {
ASSERT_DIE(f_for_stored_scope == NULL);
f_for_stored_scope = new_config->current_scope;
new_config->current_scope = new_config->current_scope->next;
} term {
ASSERT_DIE(f_for_stored_scope);
new_config->current_scope = f_for_stored_scope;
f_for_stored_scope = NULL;
}
DO cmd { DO cmd {
cf_pop_block_scope(new_config); cf_pop_block_scope(new_config);
$$ = f_for_cycle($3, $6, $9); $$ = f_for_cycle($3, $6, $9);

View File

@ -424,7 +424,7 @@ m4_undivert(112)
} }
FID_METHOD_SCOPE_INIT()m4_dnl FID_METHOD_SCOPE_INIT()m4_dnl
[INST_METHOD_OBJECT_TYPE] = { .active = 1, }, [INST_METHOD_OBJECT_TYPE] = {},
FID_METHOD_REGISTER()m4_dnl FID_METHOD_REGISTER()m4_dnl
method = lp_allocz(global_root_scope_linpool, sizeof(struct f_method) + INST_METHOD_NUM_ARGS * sizeof(enum btype)); method = lp_allocz(global_root_scope_linpool, sizeof(struct f_method) + INST_METHOD_NUM_ARGS * sizeof(enum btype));
method->new_inst = f_new_method_]]INST_NAME()[[; method->new_inst = f_new_method_]]INST_NAME()[[;

View File

@ -878,8 +878,8 @@
bug("Unsupported attribute type"); bug("Unsupported attribute type");
switch (da->type) { switch (da->type) {
case T_OPAQUE:
case T_IFACE: case T_IFACE:
case T_OPAQUE:
runtime( "Setting opaque attribute is not allowed" ); runtime( "Setting opaque attribute is not allowed" );
break; break;

View File

@ -116,6 +116,7 @@ static inline struct f_static_attr f_new_static_attr(btype type, int code, int r
{ return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; } { return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; }
struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn); struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
/* Hook for call bt_assert() function in configuration */ /* Hook for call bt_assert() function in configuration */
extern void (*bt_assert_hook)(int result, const struct f_line_item *assert); extern void (*bt_assert_hook)(int result, const struct f_line_item *assert);

View File

@ -25,9 +25,9 @@
static int static int
t_reconfig(void) t_reconfig(const void *arg)
{ {
if (!bt_config_file_parse(BT_CONFIG_FILE)) if (!bt_config_file_parse(arg))
return 0; return 0;
struct symbol *s; struct symbol *s;
@ -79,7 +79,9 @@ main(int argc, char *argv[])
if (!bt_config_file_parse(BT_CONFIG_FILE)) if (!bt_config_file_parse(BT_CONFIG_FILE))
abort(); abort();
bt_test_suite_extra(t_reconfig, 0, BT_TIMEOUT, "Testing reconfiguration"); bt_test_suite_arg_extra(t_reconfig, BT_CONFIG_FILE ".overlay", 0, BT_TIMEOUT, "Testing reconfiguration to overlay");
bt_test_suite_arg_extra(t_reconfig, BT_CONFIG_FILE, 0, BT_TIMEOUT, "Testing reconfiguration back");
bt_test_suite_arg_extra(t_reconfig, BT_CONFIG_FILE, 0, BT_TIMEOUT, "Testing reconfiguration to the same file");
struct f_bt_test_suite *t; struct f_bt_test_suite *t;
WALK_LIST(t, config->tests) WALK_LIST(t, config->tests)

3
filter/test.conf.overlay Normal file
View File

@ -0,0 +1,3 @@
attribute int peek_a_boo;
include "test.conf";

View File

@ -305,6 +305,7 @@ struct ea_class_ref {
void ea_register_init(struct ea_class *); void ea_register_init(struct ea_class *);
struct ea_class_ref *ea_register_alloc(pool *, struct ea_class); struct ea_class_ref *ea_register_alloc(pool *, struct ea_class);
struct ea_class_ref *ea_ref_class(pool *, struct ea_class *); /* Reference for an attribute alias */
#define EA_REGISTER_ALL_HELPER(x) ea_register_init(x); #define EA_REGISTER_ALL_HELPER(x) ea_register_init(x);
#define EA_REGISTER_ALL(...) MACRO_FOREACH(EA_REGISTER_ALL_HELPER, __VA_ARGS__) #define EA_REGISTER_ALL(...) MACRO_FOREACH(EA_REGISTER_ALL_HELPER, __VA_ARGS__)

View File

@ -54,9 +54,6 @@ cmd_show_symbols(struct sym_show_data *sd)
for (const struct sym_scope *scope = config->root_scope; scope; scope = scope->next) for (const struct sym_scope *scope = config->root_scope; scope; scope = scope->next)
HASH_WALK(scope->hash, next, sym) HASH_WALK(scope->hash, next, sym)
{ {
if (!sym->scope->active)
continue;
if (sd->type && (sym->class != sd->type)) if (sd->type && (sym->class != sd->type))
continue; continue;

View File

@ -573,16 +573,20 @@ static struct idm ea_class_idm;
/* Config parser lex register function */ /* Config parser lex register function */
void ea_lex_register(struct ea_class *def); void ea_lex_register(struct ea_class *def);
void ea_lex_unregister(struct ea_class *def);
static void static void
ea_class_free(struct ea_class *cl) ea_class_free(struct ea_class *cl)
{ {
RTA_LOCK;
/* No more ea class references. Unregister the attribute. */ /* No more ea class references. Unregister the attribute. */
idm_free(&ea_class_idm, cl->id); idm_free(&ea_class_idm, cl->id);
ea_class_global[cl->id] = NULL; ea_class_global[cl->id] = NULL;
if (!cl->hidden)
ea_lex_unregister(cl); /* When we start supporting full protocol removal, we may need to call
* ea_lex_unregister(cl), see where ea_lex_register() is called. */
RTA_UNLOCK;
} }
static void static void
@ -619,7 +623,7 @@ ea_class_init(void)
sizeof(*ea_class_global) * (ea_class_max = EA_CLASS_INITIAL_MAX)); sizeof(*ea_class_global) * (ea_class_max = EA_CLASS_INITIAL_MAX));
} }
static struct ea_class_ref * struct ea_class_ref *
ea_ref_class(pool *p, struct ea_class *def) ea_ref_class(pool *p, struct ea_class *def)
{ {
def->uc++; def->uc++;
@ -640,9 +644,6 @@ ea_register(pool *p, struct ea_class *def)
ASSERT_DIE(def->id < ea_class_max); ASSERT_DIE(def->id < ea_class_max);
ea_class_global[def->id] = def; ea_class_global[def->id] = def;
if (!def->hidden)
ea_lex_register(def);
return ea_ref_class(p, def); return ea_ref_class(p, def);
} }
@ -680,7 +681,12 @@ ea_register_init(struct ea_class *clp)
{ {
RTA_LOCK; RTA_LOCK;
ASSERT_DIE(!ea_class_find_by_name(clp->name)); ASSERT_DIE(!ea_class_find_by_name(clp->name));
ea_register(&root_pool, clp);
struct ea_class *def = ea_register(&root_pool, clp)->class;
if (!clp->hidden)
ea_lex_register(def);
RTA_UNLOCK; RTA_UNLOCK;
} }

View File

@ -1223,8 +1223,8 @@ bgp_register_attrs(void)
if (!bgp_attr_table[i].name) if (!bgp_attr_table[i].name)
bgp_attr_table[i] = (union bgp_attr_desc) { bgp_attr_table[i] = (union bgp_attr_desc) {
.name = mb_sprintf(&root_pool, "bgp_unknown_0x%02x", i), .name = mb_sprintf(&root_pool, "bgp_unknown_0x%02x", i),
.type = T_OPAQUE, .type = T_BYTESTRING,
.flags = BAF_OPTIONAL, .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
.readonly = 1, .readonly = 1,
.export = bgp_export_unknown, .export = bgp_export_unknown,
.encode = bgp_encode_raw, .encode = bgp_encode_raw,
@ -1236,6 +1236,12 @@ bgp_register_attrs(void)
} }
} }
struct ea_class *
bgp_find_ea_class_by_id(uint id)
{
return (id < ARRAY_SIZE(bgp_attr_table)) ? &bgp_attr_table[id].class : NULL;
}
/* /*
* Attribute export * Attribute export

View File

@ -662,6 +662,7 @@ bgp_total_aigp_metric(const rte *e)
} }
void bgp_register_attrs(void); void bgp_register_attrs(void);
struct ea_class *bgp_find_ea_class_by_id(uint id);
/* packets.c */ /* packets.c */

View File

@ -335,6 +335,19 @@ bgp_channel_end:
bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end; bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end;
custom_attr: ATTRIBUTE BGP NUM type symbol ';' {
if ($3 > 255 || $3 < 1)
cf_error("Invalid attribute number. (Given %i, must be 1-255.)", $3);
struct ea_class *ac = bgp_find_ea_class_by_id($3);
ASSERT_DIE(ac);
if ($4 != ac->type)
cf_error("Attribute %d type must be %s, not %s.", $3, f_type_name(ac->type), f_type_name($4));
ea_ref_class(new_config->pool, ac);
cf_define_symbol(new_config, $5, SYM_ATTRIBUTE, attribute, ac);
};
CF_ENUM(T_ENUM_BGP_ORIGIN, ORIGIN_, IGP, EGP, INCOMPLETE) CF_ENUM(T_ENUM_BGP_ORIGIN, ORIGIN_, IGP, EGP, INCOMPLETE)
CF_CODE CF_CODE