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:
commit
c5f6dc8142
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
@ -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">
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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()[[;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
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 *);
|
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__)
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 */
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user