... and consted some declarations.
if (l > SYM_MAX_LEN)
cf_error("Symbol too long");
- s = cfg_alloc(sizeof(struct symbol) + l);
- s->scope = conf_this_scope;
- s->class = SYM_VOID;
- s->def = NULL;
- s->aux = 0;
+ s = cfg_allocz(sizeof(struct symbol) + l + 1);
+ *s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, };
strcpy(s->name, c);
if (!new_config->sym_hash.data)
(s = HASH_FIND(cfg->sym_hash, SYM, c, 1)))
return s;
+ /* In CLI command parsing, fallback points to the current config, otherwise it is NULL. */
if (cfg->fallback &&
cfg->fallback->sym_hash.data &&
(s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1)))
return cf_find_symbol(new_config, c) ?: cf_new_symbol(c);
}
+/**
+ * cf_localize_symbol - get the local instance of given symbol
+ * @sym: the symbol to localize
+ *
+ * This functions finds the symbol that is local to current scope
+ * for purposes of cf_define_symbol().
+ */
+struct symbol *
+cf_localize_symbol(struct symbol *sym)
+{
+ /* If the symbol type is void, it has been recently allocated just in this scope. */
+ if (!sym->class)
+ return sym;
+
+ /* If the scope is the current, it is already defined in this scope. */
+ if (sym->scope == conf_this_scope)
+ cf_error("Symbol already defined");
+
+ /* Not allocated here yet, doing it now. */
+ return cf_new_symbol(sym->name);
+}
+
struct symbol *
cf_default_name(char *template, int *counter)
{
cf_error("Unable to generate default name");
}
-/**
- * cf_define_symbol - define meaning of a symbol
- * @sym: symbol to be defined
- * @type: symbol class to assign
- * @def: class dependent data
- *
- * Defines new meaning of a symbol. If the symbol is an undefined
- * one (%SYM_VOID), it's just re-defined to the new type. If it's defined
- * in different scope, a new symbol in current scope is created and the
- * meaning is assigned to it. If it's already defined in the current scope,
- * an error is reported via cf_error().
- *
- * Result: Pointer to the newly defined symbol. If we are in the top-level
- * scope, it's the same @sym as passed to the function.
- */
-struct symbol *
-cf_define_symbol(struct symbol *sym, int type, void *def)
-{
- if (sym->class)
- {
- if (sym->scope == conf_this_scope)
- cf_error("Symbol already defined");
- sym = cf_new_symbol(sym->name);
- }
- sym->class = type;
- sym->def = def;
- return sym;
-}
-
static void
cf_lex_init_kh(void)
{
struct symbol {
struct symbol *next;
struct sym_scope *scope;
- int class;
- int aux;
- uint aux2;
- void *def;
- char name[1];
+ int class; /* SYM_* */
+ uint flags; /* SYM_FLAG_* */
+
+ union {
+ struct proto_config *proto; /* For SYM_PROTO and SYM_TEMPLATE */
+ 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 f_val *val; /* For SYM_CONSTANT or SYM_VARIABLE */
+ };
+
+ char name[0];
};
struct sym_scope {
#define SYM_CONSTANT 0x200 /* 0x200-0x2ff are variable types */
#define SYM_CONSTANT_RANGE SYM_CONSTANT ... (SYM_CONSTANT | 0xff)
-#define SYM_TYPE(s) (((struct f_val *) (s)->def)->type)
-#define SYM_VAL(s) (((struct f_val *) (s)->def)->val)
+#define SYM_TYPE(s) ((s)->val->type)
+#define SYM_VAL(s) ((s)->val->val)
+
+/* Symbol flags */
+#define SYM_FLAG_SAME 0x1 /* For SYM_FUNCTION and SYM_FILTER */
struct include_file_stack {
void *buffer; /* Internal lexer state */
struct symbol *cf_get_symbol(byte *c);
struct symbol *cf_default_name(char *template, int *counter);
-struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def);
+struct symbol *cf_localize_symbol(struct symbol *sym);
+
+/**
+ * cf_define_symbol - define meaning of a symbol
+ * @sym: symbol to be defined
+ * @type: symbol class to assign
+ * @def: class dependent data
+ *
+ * Defines new meaning of a symbol. If the symbol is an undefined
+ * one (%SYM_VOID), it's just re-defined to the new type. If it's defined
+ * in different scope, a new symbol in current scope is created and the
+ * meaning is assigned to it. If it's already defined in the current scope,
+ * an error is reported via cf_error().
+ *
+ * Result: Pointer to the newly defined symbol. If we are in the top-level
+ * scope, it's the same @sym as passed to the function.
+ */
+#define cf_define_symbol(sym_, type_, var_, def_) ({ \
+ struct symbol *sym = cf_localize_symbol(sym_); \
+ sym->class = type_; \
+ sym->var_ = def_; \
+ sym; })
+
void cf_push_scope(struct symbol *);
void cf_pop_scope(void);
char *cf_symbol_class_name(struct symbol *sym);
struct f_dynamic_attr fda;
struct f_static_attr fsa;
struct f_lval flv;
- struct filter *f;
+ const struct f_line *fl;
+ const struct filter *f;
struct f_tree *e;
struct f_trie *trie;
struct f_val v;
DEFINE CF_SYM_VOID '=' term ';' {
struct f_val *val = cfg_alloc(sizeof(struct f_val));
if (f_eval(f_postfixify($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
- cf_define_symbol($2, SYM_CONSTANT | val->type, val);
+ cf_define_symbol($2, SYM_CONSTANT | val->type, val, val);
}
;
%type <x> term block cmd cmds constant constructor print_one print_list var_list var_listn function_call symbol_value bgp_path_expr bgp_path bgp_path_tail one_decl decls
%type <fda> dynamic_attr
%type <fsa> static_attr
-%type <f> filter filter_body where_filter
+%type <f> filter where_filter
+%type <fl> filter_body
%type <flv> lvalue
%type <i> type
%type <ecs> ec_kind
conf: filter_def ;
filter_def:
- FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
+ FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
filter_body {
- $2->def = $4;
- $4->name = $2->name;
- DBG( "We have new filter defined (%s)\n", $2->name );
+ struct filter *f = cfg_alloc(sizeof(struct filter));
+ *f = (struct filter) { .name = $2->name, .root = $4 };
+ $2->filter = f;
+
cf_pop_scope();
}
;
conf: custom_attr ;
custom_attr: ATTRIBUTE type CF_SYM_VOID ';' {
- cf_define_symbol($3, SYM_ATTRIBUTE, ca_lookup(new_config->pool, $3->name, $2)->fda);
+ cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda);
};
conf: bt_test_suite ;
bt_test_suite:
BT_TEST_SUITE '(' CF_SYM_FUNCTION ',' text ')' {
struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
- t->fn = $3->def;
+ t->fn = $3->function;
t->fn_name = $3->name;
t->dsc = $5;
bt_test_same:
BT_TEST_SAME '(' CF_SYM_FUNCTION ',' CF_SYM_FUNCTION ',' NUM ')' {
struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
- t->fn = $3->def;
- t->cmp = $5->def;
+ t->fn = $3->function;
+ t->cmp = $5->function;
t->result = $7;
t->fn_name = $3->name;
t->dsc = $5->name;
type CF_SYM_VOID {
struct f_val * val = cfg_alloc(sizeof(struct f_val));
val->type = T_VOID;
- $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
+ $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val, val);
DBG( "New variable %s type %x\n", $2->name, $1 );
$$ = f_new_inst(FI_SET, NULL, $2);
}
filter_body:
function_body {
- $$ = cfg_alloc(sizeof(struct filter));
- $$->name = NULL;
if ($1[0]) {
const struct f_inst *inst[2] = { $1[0], $1[1] };
- $$->root = f_postfixify_concat(inst, 2);
+ $$ = f_postfixify_concat(inst, 2);
}
else
- $$->root = f_postfixify($1[1]);
+ $$ = f_postfixify($1[1]);
}
;
filter:
CF_SYM_FILTER {
- $$ = $1->def;
+ $$ = $1->filter;
+ }
+ | filter_body {
+ struct filter *f = cfg_alloc(sizeof(struct filter));
+ *f = (struct filter) { .root = $1 };
+ $$ = f;
}
- | filter_body
;
where_filter:
conf: function_def ;
function_def:
FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name );
- $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
+ $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL);
cf_push_scope($2);
} function_params function_body {
const struct f_inst *catlist[4];
if ($5[1])
catlist[count++] = $5[1];
- $2->def = f_postfixify_concat(catlist, count);
- $2->aux2 = $4.count;
- DBG("Hmm, we've got one function here - %s\n", $2->name);
+ struct f_line *fl = f_postfixify_concat(catlist, count);
+ fl->args = $4.count;
+ $2->function = fl;
+
cf_pop_scope();
}
;
}
| CF_SYM_CONSTANT {
if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
- $$ = *(struct f_val *)($1->def);
+ $$ = *$1->val;
}
;
;
symbol_value:
- CF_SYM_CONSTANT { $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->def); }
+ CF_SYM_CONSTANT { $$ = f_new_inst(FI_CONSTANT_INDIRECT, $1->val); }
| CF_SYM_VARIABLE { $$ = f_new_inst(FI_VARIABLE, $1); }
- | CF_SYM_ATTRIBUTE { $$ = f_new_inst(FI_EA_GET, *((struct f_dynamic_attr *) $1->def)); }
+ | CF_SYM_ATTRIBUTE { $$ = f_new_inst(FI_EA_GET, *$1->attribute); }
;
static_attr:
$$ = f_new_inst(FI_CONDITION, $2, $4, $6);
}
| CF_SYM_ATTRIBUTE '=' term ';' {
- $$ = f_new_inst(FI_EA_SET, $3, *((struct f_dynamic_attr *) $1->def));
+ $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
}
| CF_SYM_VARIABLE '=' term ';' {
$$ = f_new_inst(FI_SET, $3, $1);
FID_NEW_ARGS
, const struct symbol *sym
FID_NEW_BODY
-what->valp = (what->sym = sym)->def;
+what->valp = (what->sym = sym)->val;
FID_POSTFIXIFY_BODY
-dest->items[pos].vp = (dest->items[pos].sym = what->sym)->def;
+dest->items[pos].vp = (dest->items[pos].sym = what->sym)->val;
FID_SAME_BODY
if (strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)) return 0;
FID_DUMP_BODY
/* IP->Quad implicit conversion */
if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1))
{
- *((struct f_val *) sym->def) = (struct f_val) {
+ *(sym->val) = (struct f_val) {
.type = T_QUAD,
.val.i = ipa_to_u32(v1.val.ip),
};
}
runtime( "Assigning to variable of incompatible type" );
}
- *((struct f_val *) sym->def) = v1;
+ *(sym->val) = v1;
}
/* some constants have value in a[1], some in *a[0].p, strange. */
/* Postfixify extracts the function body from the symbol */
FID_POSTFIXIFY_BODY
- dest->items[pos].lines[0] = what->sym->def;
+ dest->items[pos].lines[0] = what->sym->function;
FID_END
/* First push the body on stack */
for (const struct f_inst *inst = f1; inst; inst = inst->next)
count++;
- if (count != sym->aux2)
- cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->aux2, count);
+ if (count != sym->function->args)
+ cf_error("Function %s takes %u arguments, got %u.", sym->name, sym->function->args, count);
FID_END
/* FIXME: Optimization of function comparison. */
/* Line of instructions to be unconditionally executed one after another */
struct f_line {
uint len; /* Line length */
+ u16 args; /* Function: Args required */
struct f_line_item items[0]; /* The items themselves */
};
/* Bird Tests */
struct f_bt_test_suite {
node n; /* Node in config->tests */
- struct f_line *fn; /* Root of function */
- struct f_line *cmp; /* Compare to this function */
+ const struct f_line *fn; /* Root of function */
+ const struct f_line *cmp; /* Compare to this function */
const char *fn_name; /* Name of test */
const char *dsc; /* Description */
int result; /* Desired result */
#define P(a,b) ((a<<8) | b)
-char *
-filter_name(struct filter *filter)
+const char *
+filter_name(const struct filter *filter)
{
if (!filter)
return "ACCEPT";
/**
* filter_same - compare two filters
* @new: first filter to be compared
- * @old: second filter to be compared, notice that this filter is
- * damaged while comparing.
+ * @old: second filter to be compared
*
* Returns 1 in case filters are same, otherwise 0. If there are
* underlying bugs, it will rather say 0 on same filters than say
* 1 on different.
*/
int
-filter_same(struct filter *new, struct filter *old)
+filter_same(const struct filter *new, const struct filter *old)
{
if (old == new) /* Handle FILTER_ACCEPT and FILTER_REJECT */
return 1;
struct f_line;
struct filter {
char *name;
- struct f_line *root;
+ const struct f_line *root;
};
struct rte;
uint f_eval_int(const struct f_line *expr);
enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf);
-char *filter_name(struct filter *filter);
-int filter_same(struct filter *new, struct filter *old);
+const char *filter_name(const struct filter *filter);
+int filter_same(const struct filter *new, const struct filter *old);
int f_same(const struct f_line *f1, const struct f_line *f2);
#define FILTER_ACCEPT NULL
/* EMPTY */ {
struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
s->class = this_proto->class;
- s->def = this_proto;
+ s->proto = this_proto;
this_proto->name = s->name;
}
| CF_SYM_VOID {
- cf_define_symbol($1, this_proto->class, this_proto);
+ cf_define_symbol($1, this_proto->class, proto, this_proto);
this_proto->name = $1->name;
}
| FROM sym_proto_or_template {
struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
s->class = this_proto->class;
- s->def = this_proto;
+ s->proto = this_proto;
this_proto->name = s->name;
if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected");
- proto_copy_config(this_proto, $2->def);
+ proto_copy_config(this_proto, $2->proto);
}
| CF_SYM_VOID FROM sym_proto_or_template {
- cf_define_symbol($1, this_proto->class, this_proto);
+ cf_define_symbol($1, this_proto->class, proto, this_proto);
this_proto->name = $1->name;
if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected");
- proto_copy_config(this_proto, $3->def);
+ proto_copy_config(this_proto, $3->proto);
}
;
proto_channel: channel_start channel_opt_list channel_end;
-rtable: CF_SYM_TABLE { $$ = $1->def; } ;
+rtable: CF_SYM_TABLE { $$ = $1->table; } ;
imexport:
FILTER filter { $$ = $2; }
}
| r_args TABLE CF_SYM_TABLE {
$$ = $1;
- rt_show_add_table($$, ((struct rtable_config *)$3->def)->table);
+ rt_show_add_table($$, $3->table->table);
$$->tables_defined_by = RSD_TDB_DIRECT;
}
| r_args TABLE ALL {
}
| r_args IMPORT TABLE CF_SYM_PROTO '.' r_args_channel {
$$ = $1;
- struct proto_config *cf = (void *) $4->def;
+ struct proto_config *cf = $4->proto;
if (!cf->proto) cf_error("%s is not a protocol", $4->name);
struct channel *c = proto_find_channel_by_name(cf->proto, $6);
if (!c) cf_error("Channel %s.%s not found", $4->name, $6);
$$->filtered = 1;
}
| r_args export_mode CF_SYM_PROTO {
- struct proto_config *c = (struct proto_config *) $3->def;
+ struct proto_config *c = (struct proto_config *) $3->proto;
$$ = $1;
if ($$->export_mode) cf_error("Export specified twice");
if (!c->proto) cf_error("%s is not a protocol", $3->name);
$$->tables_defined_by = RSD_TDB_INDIRECT;
}
| r_args export_mode CF_SYM_PROTO '.' r_args_channel {
- struct proto_config *c = (struct proto_config *) $3->def;
+ struct proto_config *c = (struct proto_config *) $3->proto;
$$ = $1;
if ($$->export_mode) cf_error("Export specified twice");
if (!c->proto) cf_error("%s is not a protocol", $3->name);
$$->tables_defined_by = RSD_TDB_INDIRECT;
}
| r_args PROTOCOL CF_SYM_PROTO {
- struct proto_config *c = (struct proto_config *) $3->def;
+ struct proto_config *c = (struct proto_config *) $3->proto;
$$ = $1;
if ($$->show_protocol) cf_error("Protocol specified twice");
if (!c->proto) cf_error("%s is not a protocol", $3->name);
{
/* Found match, let's check if we can smoothly switch to new configuration */
/* No need to check description */
- nc = sym->def;
+ nc = sym->proto;
nc->proto = p;
/* We will try to reconfigure protocol p */
return;
}
- cmd(((struct proto_config *)s->def)->proto, arg, 0);
+ cmd(s->proto->proto, arg, 0);
cli_msg(0, "");
}
if (sym->class != SYM_PROTO)
cf_error("%s: Not a protocol", sym->name);
- p = ((struct proto_config *) sym->def)->proto;
+ p = sym->proto->proto;
if (!p || p->proto != pr)
cf_error("%s: Not a %s protocol", sym->name, pr->name);
}
struct proto_config *parent; /* Where channel is defined (proto or template) */
struct rtable_config *table; /* Table we're attached to */
- struct filter *in_filter, *out_filter; /* Attached filters */
+ const struct filter *in_filter, *out_filter; /* Attached filters */
struct channel_limit rx_limit; /* Limit for receiving routes from protocol
(relevant when in_keep_filtered is active) */
struct channel_limit in_limit; /* Limit for importing routes from protocol */
struct proto *proto;
struct rtable *table;
- struct filter *in_filter; /* Input filter */
- struct filter *out_filter; /* Output filter */
+ const struct filter *in_filter; /* Input filter */
+ const struct filter *out_filter; /* Output filter */
struct channel_limit rx_limit; /* Receive limit (for in_keep_filtered) */
struct channel_limit in_limit; /* Input limit */
struct channel_limit out_limit; /* Output limit */
rte *rte_get_temp(struct rta *);
void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
/* rte_update() moved to protocol.h to avoid dependency conflicts */
-int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter);
+int rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter);
rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent);
void rt_refresh_begin(rtable *t, struct channel *c);
void rt_refresh_end(rtable *t, struct channel *c);
struct rt_show_data_rtable *last_table; /* Last table in output */
struct fib_iterator fit; /* Iterator over networks in table */
int verbose, tables_defined_by;
- struct filter *filter;
+ const struct filter *filter;
struct proto *show_protocol;
struct proto *export_protocol;
struct channel *export_channel;
export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent)
{
struct proto *p = c->proto;
- struct filter *filter = c->out_filter;
+ const struct filter *filter = c->out_filter;
struct proto_stats *stats = &c->stats;
rte *rt;
int v;
{
struct proto *p = c->proto;
struct proto_stats *stats = &c->stats;
- struct filter *filter = c->in_filter;
+ const struct filter *filter = c->in_filter;
rte *dummy = NULL;
net *nn;
/* Check rtable for best route to given net whether it would be exported do p */
int
-rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
+rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter)
{
net *n = net_find(t, a);
rte *rt = n ? n->routes : NULL;
{
/* Hack that allows to 'redefine' the master table */
if ((s->class == SYM_TABLE) &&
- (s->def == new_config->def_tables[addr_type]) &&
+ (s->table == new_config->def_tables[addr_type]) &&
((addr_type == NET_IP4) || (addr_type == NET_IP6)))
- return s->def;
+ return s->table;
struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config));
- cf_define_symbol(s, SYM_TABLE, c);
+ cf_define_symbol(s, SYM_TABLE, table, c);
c->name = s->name;
c->addr_type = addr_type;
c->gc_max_ops = 1000;
rt_find_table_config(struct config *cf, char *name)
{
struct symbol *sym = cf_find_symbol(cf, name);
- return (sym && (sym->class == SYM_TABLE)) ? sym->def : NULL;
+ return (sym && (sym->class == SYM_TABLE)) ? sym->table : NULL;
}
/**
struct rtable_config *table_cf;
const char *table_expr;
- struct filter *filter;
+ const struct filter *filter;
const char *filename;
uint period;
int always_add_path;
struct mrt_dump_data {
const char *table_expr;
struct rtable *table_ptr;
- struct filter *filter;
+ const struct filter *filter;
char *filename;
};
/* Configuration information */
const char *table_expr; /* Wildcard for table name (or NULL) */
struct rtable *table_ptr; /* Explicit table (or NULL) */
- struct filter *filter; /* Optional filter */
+ const struct filter *filter; /* Optional filter */
const char *filename; /* Filename pattern */
int always_add_path; /* Always use *_ADDPATH message subtypes */
krt_export_net(struct krt_proto *p, net *net, rte **rt_free)
{
struct channel *c = p->p.main_channel;
- struct filter *filter = c->out_filter;
+ const struct filter *filter = c->out_filter;
rte *rt;
if (c->ra_mode == RA_MERGED)
static inline void
add_num_const(char *name, int val)
{
- struct symbol *s = cf_get_symbol(name);
- s->class = SYM_CONSTANT | T_INT;
- s->def = cfg_allocz(sizeof(struct f_val));
- SYM_TYPE(s) = T_INT;
- SYM_VAL(s).i = val;
+ struct f_val *v = cfg_alloc(sizeof(struct f_val));
+ *v = (struct f_val) { .type = T_INT, .val.i = val };
+ cf_define_symbol(cf_get_symbol(name), SYM_CONSTANT | T_INT, val, v);
}
/* the code of read_iproute_table() is based on