0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-09-18 19:35:20 +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;
static struct sym_scope
global_root_scope = {
.active = 1,
},
global_filter_scope = {
.active = 0,
.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 */
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;
else
scope = scope->next;
@ -735,6 +734,8 @@ ea_lex_register(struct ea_class *def)
def->sym->attribute = def;
}
#if 0
/* When we start to support complete protocol removal, we may need this function */
void
ea_lex_unregister(struct ea_class *def)
{
@ -743,19 +744,13 @@ ea_lex_unregister(struct ea_class *def)
mb_free(sym);
def->sym = NULL;
}
#endif
struct ea_class *
ea_class_find_by_name(const char *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;
struct symbol *sym = cf_find_symbol_scope(config ? config->root_scope : &global_filter_scope, name);
return sym && (sym->class == SYM_ATTRIBUTE) ? sym->attribute : NULL;
}
void f_type_methods_register(void);
@ -803,7 +798,6 @@ cf_lex_init(int is_cli, struct config *c)
BEGIN(INITIAL);
c->root_scope = c->current_scope = cfg_allocz(sizeof(struct sym_scope));
c->root_scope->active = 1;
if (is_cli)
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;
conf->current_scope = s;
s->active = 1;
s->name = sym;
s->slots = 0;
}
@ -844,10 +837,7 @@ void
cf_pop_scope(struct config *conf)
{
ASSERT(!conf->current_scope->soft_scopes);
conf->current_scope->active = 0;
conf->current_scope = conf->current_scope->next;
ASSERT(conf->current_scope);
}
@ -903,8 +893,8 @@ cf_swap_soft_scope(struct config *conf)
void
cf_enter_filters(void)
{
ASSERT_DIE(!global_filter_scope.active);
global_filter_scope.active = 1;
ASSERT_DIE(!new_config->allow_attributes);
new_config->allow_attributes = 1;
}
/**
@ -913,8 +903,8 @@ cf_enter_filters(void)
void
cf_exit_filters(void)
{
ASSERT_DIE(global_filter_scope.active);
global_filter_scope.active = 0;
ASSERT_DIE(new_config->allow_attributes);
new_config->allow_attributes = 0;
}

View File

@ -60,7 +60,8 @@
static jmp_buf conf_jmpbuf;
struct config *config, *new_config;
struct config *config;
_Thread_local struct config *new_config;
pool *config_pool;
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 *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 */
event done_event; /* Called when obstacle_count reaches zero */
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. */
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);
int config_parse(struct config *);
@ -149,7 +150,6 @@ struct sym_scope {
uint slots; /* Variable slots */
byte soft_scopes; /* Number of soft scopes above */
byte active:1; /* Currently entered */
byte block:1; /* No independent stack frame */
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.
</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
<label id="bgp-exam">

View File

@ -28,6 +28,8 @@ static struct f_method_scope {
} f_method_scope_stack[32];
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])
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)
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) {
.object = object,
.main = new_config->current_scope,
.scope = {
.next = NULL,
.hash = scope->hash,
.active = 1,
.block = 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)
{
ASSERT_DIE(FM.scope.active);
FM.scope.active = 0;
/* For argument parsing, we need to revert back to the standard symbol scope. */
new_config->current_scope = FM.main;
}
static inline void f_method_call_end(void)
{
ASSERT_DIE(f_method_scope_pos >= 0);
if (FM.scope.active) {
ASSERT_DIE(&FM.scope == new_config->current_scope);
if (&FM.scope == new_config->current_scope)
new_config->current_scope = FM.main;
FM.scope.active = 0;
}
f_method_scope_pos--;
}
@ -423,14 +420,18 @@ filter_eval:
conf: custom_attr ;
custom_attr: ATTRIBUTE type symbol ';' {
if (($3->class == SYM_ATTRIBUTE) && ($3->scope == new_config->root_scope))
cf_error("Duplicate attribute %s definition", $3->name);
cf_define_symbol(new_config, $3, SYM_ATTRIBUTE, attribute,
ea_register_alloc(new_config->pool, (struct ea_class) {
cf_enter_filters();
struct ea_class *ac = ea_class_find_by_name($3->name);
cf_exit_filters();
if (ac && (ac->type == $2))
ea_ref_class(new_config->pool, ac);
else
ac = ea_register_alloc(new_config->pool, (struct ea_class) {
.name = $3->name,
.type = $2,
})->class);
})->class;
cf_define_symbol(new_config, $3, SYM_ATTRIBUTE, attribute, ac);
};
conf: bt_test_suite ;
@ -1003,7 +1004,15 @@ cmd:
new_config->current_scope->slots += 2;
} for_var IN
/* 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 {
cf_pop_block_scope(new_config);
$$ = f_for_cycle($3, $6, $9);

View File

@ -424,7 +424,7 @@ m4_undivert(112)
}
FID_METHOD_SCOPE_INIT()m4_dnl
[INST_METHOD_OBJECT_TYPE] = { .active = 1, },
[INST_METHOD_OBJECT_TYPE] = {},
FID_METHOD_REGISTER()m4_dnl
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()[[;

View File

@ -878,8 +878,8 @@
bug("Unsupported attribute type");
switch (da->type) {
case T_OPAQUE:
case T_IFACE:
case T_OPAQUE:
runtime( "Setting opaque attribute is not allowed" );
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 }; }
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 */
extern void (*bt_assert_hook)(int result, const struct f_line_item *assert);

View File

@ -25,9 +25,9 @@
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;
struct symbol *s;
@ -79,7 +79,9 @@ main(int argc, char *argv[])
if (!bt_config_file_parse(BT_CONFIG_FILE))
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;
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 *);
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(...) 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)
HASH_WALK(scope->hash, next, sym)
{
if (!sym->scope->active)
continue;
if (sd->type && (sym->class != sd->type))
continue;

View File

@ -573,16 +573,20 @@ static struct idm ea_class_idm;
/* Config parser lex register function */
void ea_lex_register(struct ea_class *def);
void ea_lex_unregister(struct ea_class *def);
static void
ea_class_free(struct ea_class *cl)
{
RTA_LOCK;
/* No more ea class references. Unregister the attribute. */
idm_free(&ea_class_idm, cl->id);
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
@ -619,7 +623,7 @@ ea_class_init(void)
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)
{
def->uc++;
@ -640,9 +644,6 @@ ea_register(pool *p, struct ea_class *def)
ASSERT_DIE(def->id < ea_class_max);
ea_class_global[def->id] = def;
if (!def->hidden)
ea_lex_register(def);
return ea_ref_class(p, def);
}
@ -680,7 +681,12 @@ ea_register_init(struct ea_class *clp)
{
RTA_LOCK;
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;
}

View File

@ -1223,8 +1223,8 @@ bgp_register_attrs(void)
if (!bgp_attr_table[i].name)
bgp_attr_table[i] = (union bgp_attr_desc) {
.name = mb_sprintf(&root_pool, "bgp_unknown_0x%02x", i),
.type = T_OPAQUE,
.flags = BAF_OPTIONAL,
.type = T_BYTESTRING,
.flags = BAF_OPTIONAL | BAF_TRANSITIVE,
.readonly = 1,
.export = bgp_export_unknown,
.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

View File

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

View File

@ -335,6 +335,19 @@ 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_CODE