mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2025-01-02 23:21:54 +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:
commit
c5f6dc8142
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
};
|
||||
|
@ -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">
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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()[[;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
3
filter/test.conf.overlay
Normal file
@ -0,0 +1,3 @@
|
||||
attribute int peek_a_boo;
|
||||
|
||||
include "test.conf";
|
@ -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__)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user