From: Maria Matejka Date: Sat, 28 Oct 2023 21:42:21 +0000 (+0200) Subject: Merge commit 'fc9d471b' into thread-next X-Git-Tag: v3.0.0~376 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1a49a4aea8f96701d9de291e39271d8aa30f2ee5;p=thirdparty%2Fbird.git Merge commit 'fc9d471b' into thread-next Conflicts: conf/cf-lex.l conf/conf.h filter/config.Y filter/data.c filter/data.h --- 1a49a4aea8f96701d9de291e39271d8aa30f2ee5 diff --cc conf/cf-lex.l index 179b66a49,c4760e403..203991655 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@@ -78,19 -78,9 +78,20 @@@ static uint cf_hash(const byte *c) HASH_DEFINE_REHASH_FN(SYM, struct symbol) -struct sym_scope *global_root_scope; +/* Global symbol scopes */ - static pool *global_root_scope_pool; + 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, + }; + +/* Local symbol scope: TODO this isn't thread-safe */ +struct sym_scope *conf_this_scope; linpool *cfg_mem; @@@ -594,25 -584,6 +595,31 @@@ cf_new_symbol(struct sym_scope *scope, return s; } - static struct symbol * ++struct symbol * +cf_root_symbol(const byte *c, struct sym_scope *ss) +{ + uint l = strlen(c); + if (l > SYM_MAX_LEN) + bug("Root symbol %s too long", c); + - struct symbol *s = mb_alloc(&root_pool, sizeof(struct symbol) + l + 1); ++ if (!global_root_scope_pool) ++ { ++ global_root_scope_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Keywords pool"); ++ global_root_scope_linpool = lp_new(global_root_scope_pool); ++ } ++ ++ struct symbol *s = lp_alloc(global_root_scope_linpool, sizeof(struct symbol) + l + 1); + *s = (struct symbol) { .scope = ss, .class = SYM_VOID, }; + memcpy(s->name, c, l+1); + + if (!ss->hash.data) + HASH_INIT(ss->hash, &root_pool, SYM_ORDER); + + HASH_INSERT2(ss->hash, SYM, &root_pool, s); + return s; +} + + /** * cf_find_symbol_scope - find a symbol by name * @scope: config scope @@@ -722,37 -695,8 +731,39 @@@ cf_lex_symbol(const char *data } } +void +ea_lex_register(struct ea_class *def) +{ + def->sym = cf_root_symbol(def->name, &global_filter_scope); + def->sym->class = SYM_ATTRIBUTE; + def->sym->attribute = def; +} + +void +ea_lex_unregister(struct ea_class *def) +{ + struct symbol *sym = def->sym; + HASH_REMOVE2(global_filter_scope.hash, SYM, &root_pool, sym); + mb_free(sym); + def->sym = NULL; +} + +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; +} + + void f_type_methods_register(void); + /** * cf_lex_init - initialize the lexer * @is_cli: true if we're going to parse CLI command, false for configuration @@@ -764,19 -708,22 +775,19 @@@ void cf_lex_init(int is_cli, struct config *c) { -- if (!global_root_scope_pool) ++ if (!global_root_scope.readonly) { - global_root_scope_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Keywords pool"); - global_root_scope_pool = rp_new(&root_pool, "Keywords pool"); - global_root_scope_linpool = lp_new(global_root_scope_pool); - global_root_scope = lp_allocz(global_root_scope_linpool, sizeof(*global_root_scope)); -- for (const struct keyword *k = keyword_list; k->name; k++) { - struct symbol *sym = cf_new_symbol(global_root_scope, global_root_scope_pool, global_root_scope_linpool, k->name); - sym->class = SYM_KEYWORD; - sym->keyword = k; + struct symbol *s = cf_root_symbol(k->name, &global_root_scope); + s->class = SYM_KEYWORD; + s->keyword = k; } - global_root_scope->readonly = 1; + global_root_scope.readonly = 1; + global_filter_scope.readonly = 1; + + f_type_methods_register(); } ifs_head = ifs = push_ifs(NULL); diff --cc conf/conf.h index f7833d9e1,1413cb581..762ba3c13 --- a/conf/conf.h +++ b/conf/conf.h @@@ -147,9 -145,10 +149,12 @@@ struct sym_scope byte readonly:1; /* Do not add new symbols */ }; -extern struct sym_scope *global_root_scope; +void cf_enter_filters(void); +void cf_exit_filters(void); + + extern pool *global_root_scope_pool; + extern linpool *global_root_scope_linpool; + struct bytestring { size_t length; byte data[]; @@@ -213,6 -213,9 +219,10 @@@ struct symbol *cf_localize_symbol(struc static inline int cf_symbol_is_local(struct config *conf, struct symbol *sym) { return (sym->scope == conf->current_scope) && !conf->current_scope->soft_scopes; } + /* internal */ + struct symbol *cf_new_symbol(struct sym_scope *scope, pool *p, struct linpool *lp, const byte *c); ++struct symbol *cf_root_symbol(const byte *, struct sym_scope *); + /** * cf_define_symbol - define meaning of a symbol * @sym: symbol to be defined diff --cc conf/gen_parser.m4 index af4b14554,80071aefa..b7167d7a5 --- a/conf/gen_parser.m4 +++ b/conf/gen_parser.m4 @@@ -29,11 -29,19 +29,13 @@@ m4_define(CF_END, `m4_divert(-1)' m4_define(CF_itera, `m4_ifelse($#, 1, [[CF_iter($1)]], [[CF_iter($1)[[]]CF_itera(m4_shift($@))]])') m4_define(CF_iterate, `m4_define([[CF_iter]], m4_defn([[$1]]))CF_itera($2)') -m4_define(CF_append, `m4_define([[$1]], m4_ifdef([[$1]], m4_defn([[$1]])[[$3]])[[$2]])') - -# Keywords act as %token -m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_append([[CF_kw_rule]],$1,[[ | ]])m4_define([[CF_toks]],CF_toks $1)]])') +# Keywords act as untyped %token +m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)m4_define([[CF_toks]],CF_toks $1)]])') m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks )DNL') + m4_define(CF_METHODS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks + )DNL') -m4_define(CF_keywd2, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)m4_define([[CF_toks]],CF_toks $1)]])') -m4_define(CF_KEYWORDS_EXCLUSIVE, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd2]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks -)DNL') - # CLI commands m4_define(CF_CLI, `m4_define([[CF_cmd]], cmd_[[]]m4_translit($1, [[ ]], _))DNL m4_divert(2)CF_KEYWORDS(m4_translit($1, [[ ]], [[,]])) diff --cc filter/config.Y index aededce0e,c15814fd3..4ce9ee0f7 --- a/filter/config.Y +++ b/filter/config.Y @@@ -209,33 -244,21 +244,19 @@@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u return t; } - static inline struct f_inst * - f_generate_empty(const struct symbol *sym) - { - if (sym->class != SYM_ATTRIBUTE) - cf_error("Can't empty %s: not an attribute", sym->name); - - const struct ea_class *def = sym->attribute; - const struct f_val empty = f_get_empty(def->type); - if (empty.type == T_VOID) - cf_error("Can't empty attribute %s", def->name); - - return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), def); - } - static inline struct f_inst * -f_const_empty(enum f_type t) +f_implicit_roa_check(struct rtable_config *tab) { - switch (t) { - case T_PATH: - case T_CLIST: - case T_ECLIST: - case T_LCLIST: - return f_new_inst(FI_CONSTANT, (struct f_val) { - .type = t, - .val.ad = &null_adata, - }); - default: - return f_new_inst(FI_CONSTANT, (struct f_val) {}); - } + const struct ea_class *def = ea_class_find("bgp_path"); + if (!def) + cf_error("Fatal: Couldn't find BGP path attribute definition."); + + struct f_static_attr fsa = f_new_static_attr(T_NET, SA_NET, 1); + + return f_new_inst(FI_ROA_CHECK, + f_new_inst(FI_RTA_GET, fsa), + f_new_inst(FI_AS_PATH_LAST, f_new_inst(FI_EA_GET, def)), + tab); } /* @@@ -347,32 -351,35 +368,32 @@@ assert_assign(struct f_lval *lval, stru CF_DECLS -CF_KEYWORDS_EXCLUSIVE(IN) CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, ACCEPT, REJECT, ERROR, - INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC, + INT, BOOL, IP, PREFIX, RD, PAIR, QUAD, EC, LC, SET, STRING, BYTESTRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST, IF, THEN, ELSE, CASE, - FOR, DO, + FOR, IN, DO, TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, - FROM, GW, NET, MASK, PROTO, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, - ROA_CHECK, ASN, SRC, DST, - IS_V4, IS_V6, - LEN, MAXLEN, - DATA, DATA1, DATA2, - FROM, GW, NET, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, ONLINK, - PREFERENCE, ++ FROM, GW, NET, PROTO, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, + ROA_CHECK, DEFINED, ADD, DELETE, RESET, - PREPEND, FIRST, LAST, LAST_NONAGGREGATED, - MIN, MAX, + PREPEND, EMPTY, FILTER, WHERE, EVAL, ATTRIBUTE, FROM_HEX, - BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT) + BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT, STACKS) + CF_METHODS(IS_V4, TYPE, IP, RD, LEN, MAXLEN, ASN, SRC, DST, MASK, + FIRST, LAST, LAST_NONAGGREGATED, DATA, DATA1, DATA2, MIN, MAX, + EMPTY, PREPEND, ADD, DELETE, FILTER) + %nonassoc THEN %nonassoc ELSE %type cmds_int cmd_prep - %type term term_bs cmd cmd_var cmds cmds_scoped constant constructor print_list var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail method_cmd method_term + %type term term_bs cmd cmd_var cmds cmds_scoped constant constructor print_list var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont -%type dynamic_attr %type static_attr %type filter where_filter %type filter_body function_body @@@ -401,8 -402,8 +422,9 @@@ conf: filter_def filter_def: FILTER symbol { $2 = cf_define_symbol(new_config, $2, SYM_FILTER, filter, NULL); + cf_enter_filters(); cf_push_scope( new_config, $2 ); + this_function = NULL; } filter_body { struct filter *f = cfg_alloc(sizeof(struct filter)); *f = (struct filter) { .sym = $2, .root = $4 }; @@@ -532,8 -525,8 +554,9 @@@ filter $$ = $1->filter; } | { + cf_enter_filters(); cf_push_scope(new_config, NULL); + this_function = NULL; } filter_body { struct filter *f = cfg_alloc(sizeof(struct filter)); *f = (struct filter) { .root = $2 }; @@@ -562,12 -551,17 +585,18 @@@ function_body ; conf: function_def ; + maybe_type: + /* EMPTY */ { $$ = T_VOID; } + | type { $$ = $1; } + ; + function_def: - FUNCTION symbol { - DBG( "Beginning of function %s\n", $2->name ); - $2 = cf_define_symbol(new_config, $2, SYM_FUNCTION, function, NULL); + FUNCTION maybe_type symbol { + DBG( "Beginning of function %s\n", $3->name ); + this_function = cf_define_symbol(new_config, $3, SYM_FUNCTION, function, NULL); + /* if ($2 == T_VOID) cf_warn("Support for functions without explicit return type will be removed soon" ); */ + cf_enter_filters(); - cf_push_scope(new_config, $2); + cf_push_scope(new_config, this_function); } function_args { /* Make dummy f_line for storing function prototype */ struct f_line *dummy = cfg_allocz(sizeof(struct f_line)); @@@ -583,11 -579,11 +614,12 @@@ dummy->args++; } } function_body { - $6->args = $2->function->args; - $6->arg_list = $2->function->arg_list; - $2->function = $6; + $7->args = this_function->function->args; + $7->arg_list = this_function->function->arg_list; + $7->return_type = this_function->function->return_type; + $3->function = $7; cf_pop_scope(new_config); + cf_exit_filters(); } ; @@@ -866,36 -865,23 +898,21 @@@ static_attr | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); } | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); } | WEIGHT { $$ = f_new_static_attr(T_INT, SA_WEIGHT, 0); } - | PREFERENCE { $$ = f_new_static_attr(T_INT, SA_PREF, 0); } | GW_MPLS { $$ = f_new_static_attr(T_INT, SA_GW_MPLS, 0); } - | ONLINK { $$ = f_new_static_attr(T_BOOL, SA_ONLINK, 0); } ; - method_term: - IS_V4 { $$ = f_new_inst(FI_IS_V4, FM.object); } - | TYPE { $$ = f_new_inst(FI_TYPE, FM.object); } - | IP { $$ = f_new_inst(FI_IP, FM.object); } - | RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, FM.object); } - | LEN { $$ = f_new_inst(FI_LENGTH, FM.object); } - | MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, FM.object); } - | ASN { $$ = f_new_inst(FI_ASN, FM.object); } - | SRC { $$ = f_new_inst(FI_NET_SRC, FM.object); } - | DST { $$ = f_new_inst(FI_NET_DST, FM.object); } - | MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, FM.object, $3); } - | FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, FM.object); } - | LAST { $$ = f_new_inst(FI_AS_PATH_LAST, FM.object); } - | LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, FM.object); } - | DATA { $$ = f_new_inst(FI_PAIR_DATA, FM.object); } - | DATA1 { $$ = f_new_inst(FI_LC_DATA1, FM.object); } - | DATA2 { $$ = f_new_inst(FI_LC_DATA2, FM.object); } - | MIN { $$ = f_new_inst(FI_MIN, FM.object); } - | MAX { $$ = f_new_inst(FI_MAX, FM.object); } - ; - - method_cmd: - EMPTY { $$ = f_new_inst(FI_CONSTANT, f_get_empty(FM.object->i_FI_EA_GET.da->type)); } - | PREPEND '(' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, FM.object, $3 ); } - | ADD '(' term ')' { $$ = f_new_inst(FI_CLIST_ADD, FM.object, $3 ); } - | DELETE '(' term ')' { $$ = f_new_inst(FI_CLIST_DEL, FM.object, $3 ); } - | FILTER '(' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, FM.object, $3 ); } + term_dot_method: term '.' { f_method_call_start($1); } method_name_cont { $$ = $4; }; + method_name_cont: + CF_SYM_METHOD_BARE { + $$ = $1->method->new_inst(FM.object, NULL); + f_method_call_end(); + } + | CF_SYM_METHOD_ARGS { + f_method_call_args(); + } '(' var_list ')' { + $$ = $1->method->new_inst(FM.object, $4); + f_method_call_end(); + } ; term: @@@ -925,24 -909,47 +942,45 @@@ | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); } - | term '.' { - f_push_method_scope($1); - } method_term { - f_pop_method_scope(); - $$ = $4; - } - | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); } - + | term_dot_method - | '+' EMPTY '+' { $$ = f_const_empty(T_PATH); } - | '-' EMPTY '-' { $$ = f_const_empty(T_CLIST); } - | '-' '-' EMPTY '-' '-' { $$ = f_const_empty(T_ECLIST); } - | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_const_empty(T_LCLIST); } + | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_PATH)); } + | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_CLIST)); } + | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_ECLIST)); } + | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_get_empty(T_LCLIST)); } | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); } - | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); } - | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); } - | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); } + | ADD '(' term ',' term ')' { + switch ($3->type) { + case T_CLIST: $$ = f_new_inst(FI_CLIST_ADD, $3, $5); break; + case T_ECLIST: $$ = f_new_inst(FI_ECLIST_ADD, $3, $5); break; + case T_LCLIST: $$ = f_new_inst(FI_LCLIST_ADD, $3, $5); break; + default: cf_error("Can't add to type %s", f_type_name($3->type)); + } + cf_warn("add(x,y) function is deprecated, please use x.add(y)"); + } + | DELETE '(' term ',' term ')' { + switch ($3->type) { + case T_PATH: $$ = f_new_inst(FI_PATH_DEL, $3, $5); break; + case T_CLIST: $$ = f_new_inst(FI_CLIST_DEL, $3, $5); break; + case T_ECLIST: $$ = f_new_inst(FI_ECLIST_DEL, $3, $5); break; + case T_LCLIST: $$ = f_new_inst(FI_LCLIST_DEL, $3, $5); break; + default: cf_error("Can't delete from type %s", f_type_name($3->type)); + } + cf_warn("delete(x,y) function is deprecated, please use x.delete(y)"); + } + | FILTER '(' term ',' term ')' { + switch ($3->type) { + case T_PATH: $$ = f_new_inst(FI_PATH_FILTER, $3, $5); break; + case T_CLIST: $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); break; + case T_ECLIST: $$ = f_new_inst(FI_ECLIST_FILTER, $3, $5); break; + case T_LCLIST: $$ = f_new_inst(FI_LCLIST_FILTER, $3, $5); break; + default: cf_error("Can't filter type %s", f_type_name($3->type)); + } + cf_warn("filter(x,y) function is deprecated, please use x.filter(y)"); + } - | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); } - | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); } + | ROA_CHECK '(' rtable ')' { $$ = f_implicit_roa_check($3); } + | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK, $5, $7, $3); } | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); } @@@ -1024,8 -1029,23 +1062,20 @@@ cmd } | RETURN term ';' { DBG( "Ook, we'll return the value\n" ); + if (!this_function) + cf_error("Can't return from a non-function, use accept or reject instead."); + if (this_function->function->return_type == T_VOID) + { + if ($2->type != T_VOID) + cf_warn("Inferring function %s return type from its return value: %s", this_function->name, f_type_name($2->type)); + ((struct f_line *) this_function->function)->return_type = $2->type; + } + else if (this_function->function->return_type != $2->type) + cf_error("Can't return type %s from function %s, expected %s", + f_type_name($2->type), this_function->name, f_type_name(this_function->function->return_type)); + $$ = f_new_inst(FI_RETURN, $2); } - | dynamic_attr '=' term ';' { - $$ = f_new_inst(FI_EA_SET, $3, $1); - } | static_attr '=' term ';' { if ($1.readonly) cf_error( "This static attribute is read-only."); diff --cc filter/data.c index 68f834a20,581150a2c..d700f7d2b --- a/filter/data.c +++ b/filter/data.c @@@ -612,76 -621,3 +612,75 @@@ val_dump(const struct f_val *v) val_format(v, &b); return val_dump_buffer; } + - +struct f_val * +lp_val_copy(struct linpool *lp, const struct f_val *v) +{ + switch (v->type) + { + case T_VOID: + case T_BOOL: + case T_INT: + case T_IP: + case T_PAIR: + case T_QUAD: + case T_EC: + case T_LC: + case T_RD: + case T_ENUM: + case T_PATH_MASK_ITEM: + /* These aren't embedded but there is no need to copy them */ + case T_SET: + case T_PREFIX_SET: + case T_PATH_MASK: + case T_IFACE: + { + struct f_val *out = lp_alloc(lp, sizeof(*out)); + *out = *v; + return out; + } + + case T_NET: + { + struct { + struct f_val val; + net_addr net[0]; + } *out = lp_alloc(lp, sizeof(*out) + v->val.net->length); + out->val = *v; + out->val.val.net = out->net; + net_copy(out->net, v->val.net); + return &out->val; + } + + case T_STRING: + { + uint len = strlen(v->val.s); + struct { + struct f_val val; + char buf[0]; + } *out = lp_alloc(lp, sizeof(*out) + len + 1); + out->val = *v; + out->val.val.s = out->buf; + memcpy(out->buf, v->val.s, len+1); + return &out->val; + } + + case T_PATH: + case T_CLIST: + case T_ECLIST: + case T_LCLIST: + { + struct { + struct f_val val; + struct adata ad; + } *out = lp_alloc(lp, sizeof(*out) + v->val.ad->length); + out->val = *v; + out->val.val.ad = &out->ad; + memcpy(&out->ad, v->val.ad, v->val.ad->length); + return &out->val; + } + + default: + bug("Unknown type in value copy: %d", v->type); + } +} diff --cc filter/data.h index 462acf614,baa7114c4..b668ead05 --- a/filter/data.h +++ b/filter/data.h @@@ -11,20 -11,99 +11,26 @@@ #define _BIRD_FILTER_DATA_H_ #include "nest/bird.h" - -/* Type numbers must be in 0..0xff range */ -#define T_MASK 0xff - -/* Internal types */ -enum f_type { -/* Nothing. Simply nothing. */ - T_VOID = 0, - -/* User visible types, which fit in int */ - T_INT = 0x10, - T_BOOL = 0x11, - T_PAIR = 0x12, /* Notice that pair is stored as integer: first << 16 | second */ - T_QUAD = 0x13, - -/* Put enumerational types in 0x30..0x3f range */ - T_ENUM_LO = 0x30, - T_ENUM_HI = 0x3f, - - T_ENUM_RTS = 0x30, - T_ENUM_BGP_ORIGIN = 0x31, - T_ENUM_SCOPE = 0x32, - T_ENUM_RTC = 0x33, - T_ENUM_RTD = 0x34, - T_ENUM_ROA = 0x35, - T_ENUM_NETTYPE = 0x36, - T_ENUM_RA_PREFERENCE = 0x37, - T_ENUM_AF = 0x38, - -/* new enums go here */ - T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */ - -#define T_ENUM T_ENUM_LO ... T_ENUM_HI - -/* Bigger ones */ - T_IP = 0x20, - T_NET = 0x21, - T_STRING = 0x22, - T_PATH_MASK = 0x23, /* mask for BGP path */ - T_PATH = 0x24, /* BGP path */ - T_CLIST = 0x25, /* Community list */ - T_EC = 0x26, /* Extended community value, u64 */ - T_ECLIST = 0x27, /* Extended community list */ - T_LC = 0x28, /* Large community value, lcomm */ - T_LCLIST = 0x29, /* Large community list */ - T_RD = 0x2a, /* Route distinguisher for VPN addresses */ - T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */ - T_BYTESTRING = 0x2c, - - T_SET = 0x80, - T_PREFIX_SET = 0x81, -} PACKED; +#include "lib/type.h" + struct f_method { + struct symbol *sym; + struct f_inst *(*new_inst)(struct f_inst *obj, struct f_inst *args); + uint arg_num; + }; + /* Filter value; size of this affects filter memory consumption */ struct f_val { - enum f_type type; /* T_* */ - union { - uint i; - u64 ec; - lcomm lc; - ip_addr ip; - const net_addr *net; - const char *s; - const struct bytestring *bs; - const struct f_tree *t; - const struct f_trie *ti; - const struct adata *ad; - const struct f_path_mask *path_mask; - struct f_path_mask_item pmi; - } val; + btype type; /* T_* */ + union bval_long val; }; -/* Dynamic attribute definition (eattrs) */ -struct f_dynamic_attr { - u8 type; /* EA type (EAF_*) */ - u8 bit; /* For bitfield accessors */ - enum f_type f_type; /* Filter type */ - uint ea_code; /* EA code */ -}; +#define fputip(a) ({ ip_addr *ax = falloc(sizeof(*ax)); *ax = (a); ax; }) enum f_sa_code { - SA_FROM = 1, - SA_GW, + SA_GW = 1, SA_NET, SA_PROTO, - SA_SOURCE, - SA_SCOPE, SA_DEST, SA_IFNAME, SA_IFINDEX, @@@ -209,9 -282,9 +215,9 @@@ trie_match_next_longest_ip6(net_addr_ip #define F_CMP_ERROR 999 -const char *f_type_name(enum f_type t); -enum f_type f_type_element_type(enum f_type t); -struct sym_scope *f_type_method_scope(enum f_type t); +const char *f_type_name(btype t); - +enum btype f_type_element_type(btype t); ++struct sym_scope *f_type_method_scope(btype t); int val_same(const struct f_val *v1, const struct f_val *v2); int val_compare(const struct f_val *v1, const struct f_val *v2); diff --cc filter/decl.m4 index ed7630fc9,46429f6ae..890056875 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@@ -264,9 -275,17 +276,17 @@@ FID_INTERPRET_BODY()' m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], "symbol %s", item->sym->name)') m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], "route table %s", item->rtc->name)') m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, f1->sa.sa_code != f2->sa.sa_code,,)') -m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, f1->da.ea_code != f2->da.ea_code,,)') +m4_define(DYNAMIC_ATTR, `FID_MEMBER(const struct ea_class *, da, f1->da != f2->da,,)') m4_define(ACCESS_RTE, `FID_HIC(,[[do { if (!fs->rte) runtime("No route to access"); } while (0)]],NEVER_CONSTANT())') + # Method constructor block + m4_define(METHOD_CONSTRUCTOR, `m4_dnl + FID_NEW_METHOD()m4_dnl + if (args) cf_error("Too many arguments"); + m4_define([[INST_IS_METHOD]]) + m4_define([[INST_METHOD_NAME]],$1) + FID_INTERPRET_BODY()') + # 2) Code wrapping # The code produced in 1xx temporary diversions is a raw code without # any auxiliary commands and syntactical structures around. When the @@@ -362,6 -385,35 +386,33 @@@ m4_undivert(102)m4_dn } ]]) + m4_ifdef([[INST_IS_METHOD]],m4_dnl + FID_METHOD()m4_dnl + [[struct f_inst * NONNULL(1) + f_new_method_]]INST_NAME()[[(struct f_inst *obj, struct f_inst *args) + { + /* Unwind the arguments (INST_METHOD_NUM_ARGS) */ + m4_undivert(111)m4_dnl + return f_new_inst(INST_NAME, obj + m4_undivert(112) + ); + } + + FID_METHOD_SCOPE_INIT()m4_dnl + [INST_METHOD_OBJECT_TYPE] = {}, + FID_METHOD_REGISTER()m4_dnl - sym = cf_new_symbol(&f_type_method_scopes[INST_METHOD_OBJECT_TYPE], - global_root_scope_pool, global_root_scope_linpool, - INST_METHOD_NAME); ++ sym = cf_root_symbol(INST_METHOD_NAME, &f_type_method_scopes[INST_METHOD_OBJECT_TYPE]); + sym->class = SYM_METHOD; + sym->method = method = lp_allocz(global_root_scope_linpool, sizeof(struct f_method)); + + *method = (struct f_method) { + .sym = sym, + .new_inst = f_new_method_]]INST_NAME()[[, + .arg_num = INST_METHOD_NUM_ARGS, + }; + + ]])m4_dnl + FID_DUMP_CALLER()m4_dnl Case in another big switch used in instruction dumping (debug) case INST_NAME(): f_dump_line_item_]]INST_NAME()[[(item, indent + 1); break; @@@ -538,6 -592,37 +591,37 @@@ FID_WR_PUT(3 #undef v3 #undef vv + /* Method constructor wrappers */ + FID_WR_PUT(11) + + #if defined(__GNUC__) && __GNUC__ >= 6 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Woverride-init" + #endif + + static struct sym_scope f_type_method_scopes[] = { + FID_WR_PUT(12) + }; + + #if defined(__GNUC__) && __GNUC__ >= 6 + #pragma GCC diagnostic pop + #endif + -struct sym_scope *f_type_method_scope(enum f_type t) ++struct sym_scope *f_type_method_scope(enum btype t) + { + return (t < ARRAY_SIZE(f_type_method_scopes)) ? &f_type_method_scopes[t] : NULL; + } + + void f_type_methods_register(void) + { + struct symbol *sym; + struct f_method *method; + FID_WR_PUT(13) + + for (uint i = 0; i < ARRAY_SIZE(f_type_method_scopes); i++) + f_type_method_scopes[i].readonly = 1; + } + /* Line dumpers */ #define INDENT (((const char *) f_dump_line_indent_str) + sizeof(f_dump_line_indent_str) - (indent) - 1) static const char f_dump_line_indent_str[] = " "; diff --cc filter/f-inst.c index de5314fc3,16d01e4d2..8a00438b7 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@@ -70,7 -70,10 +70,9 @@@ * m4_dnl DYNAMIC_ATTR; dynamic attribute definition * m4_dnl RTC; route table config * m4_dnl ACCESS_RTE; this instruction needs route - * m4_dnl ACCESS_EATTRS; this instruction needs extended attributes * + * m4_dnl METHOD_CONSTRUCTOR(name); this instruction is in fact a method of the first argument's type; register it with the given name for that type + * * m4_dnl FID_MEMBER( custom instruction member * m4_dnl C type, for storage in structs * m4_dnl name, how the member is named @@@ -533,7 -523,7 +530,7 @@@ /* New variable is always the last on stack */ uint pos = curline.vbase + sym->offset; -- fstk->vstk[pos] = (struct f_val) { }; ++ fstk->vstk[pos] = f_get_empty(sym->class & 0xff); fstk->vcnt = pos + 1; } @@@ -934,33 -992,40 +955,51 @@@ INST(FI_EA_UNSET, 0, 0) { DYNAMIC_ATTR; ACCESS_RTE; - ACCESS_EATTRS; - f_rta_cow(fs); - ea_unset_attr(fs->eattrs, fs->pool, 1, da.ea_code); + ea_unset_attr(&fs->rte->attrs, 1, da); + } + + INST(FI_DEFAULT, 2, 1) { + ARG_ANY(1); + ARG_ANY(2); + RESULT_TYPE(f_type_element_type(v2.type)); + + log(L_INFO "Type of arg 1 is: %d", v1.type); + + if (v1.type == T_VOID) + RESULT_VAL(v2); + else + RESULT_VAL(v1); } - INST(FI_LENGTH, 1, 1) { /* Get length of */ - ARG_ANY(1); - switch(v1.type) { - case T_NET: RESULT(T_INT, i, net_pxlen(v1.val.net)); break; - case T_PATH: RESULT(T_INT, i, as_path_getlen(v1.val.ad)); break; - case T_CLIST: RESULT(T_INT, i, int_set_get_size(v1.val.ad)); break; - case T_ECLIST: RESULT(T_INT, i, ec_set_get_size(v1.val.ad)); break; - case T_LCLIST: RESULT(T_INT, i, lc_set_get_size(v1.val.ad)); break; - default: runtime( "Prefix, path, clist or eclist expected" ); - } + INST(FI_NET_LENGTH, 1, 1) { /* Get length of */ + ARG(1, T_NET); + METHOD_CONSTRUCTOR("len"); + RESULT(T_INT, i, net_pxlen(v1.val.net)); + } + + INST(FI_PATH_LENGTH, 1, 1) { /* Get length of */ + ARG(1, T_PATH); + METHOD_CONSTRUCTOR("len"); + RESULT(T_INT, i, as_path_getlen(v1.val.ad)); + } + + INST(FI_CLIST_LENGTH, 1, 1) { /* Get length of */ + ARG(1, T_CLIST); + METHOD_CONSTRUCTOR("len"); + RESULT(T_INT, i, int_set_get_size(v1.val.ad)); + } + + INST(FI_ECLIST_LENGTH, 1, 1) { /* Get length of */ + ARG(1, T_ECLIST); + METHOD_CONSTRUCTOR("len"); + RESULT(T_INT, i, ec_set_get_size(v1.val.ad)); + } + + INST(FI_LCLIST_LENGTH, 1, 1) { /* Get length of */ + ARG(1, T_LCLIST); + METHOD_CONSTRUCTOR("len"); + RESULT(T_INT, i, lc_set_get_size(v1.val.ad)); } INST(FI_NET_SRC, 1, 1) { /* Get src prefix */ @@@ -1463,34 -1506,64 +1481,34 @@@ struct f_val dummy; if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST)) - RESULT_(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]); + RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]); else runtime("Can't filter pair"); - } + } - else if (v1.type == T_ECLIST) - { + INST(FI_ECLIST_FILTER, 2, 1) { + ARG(1, T_ECLIST); + ARG_ANY(2); + METHOD_CONSTRUCTOR("filter"); /* v2.val is either EC or EC-set */ if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST)) - RESULT_(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]); + RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]); else runtime("Can't filter ec"); - } + } - else if (v1.type == T_LCLIST) - { + INST(FI_LCLIST_FILTER, 2, 1) { + ARG(1, T_LCLIST); + ARG_ANY(2); + METHOD_CONSTRUCTOR("filter"); /* v2.val is either LC or LC-set */ if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST)) - RESULT_(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]); + RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]); else runtime("Can't filter lc"); - } - - else - runtime("Can't filter non-[e|l]clist"); } - INST(FI_ROA_CHECK_IMPLICIT, 0, 1) { /* ROA Check */ - NEVER_CONSTANT; - RTC(1); - struct rtable *table = rtc->table; - ACCESS_RTE; - ACCESS_EATTRS; - const net_addr *net = (*fs->rte)->net->n.addr; - - /* We ignore temporary attributes, probably not a problem here */ - /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */ - eattr *e = ea_find(*fs->eattrs, EA_CODE(PROTOCOL_BGP, 0x02)); - - if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH)) - runtime("Missing AS_PATH attribute"); - - u32 as = 0; - as_path_get_last(e->u.ptr, &as); - - if (!table) - runtime("Missing ROA table"); - - if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6) - runtime("Table type must be either ROA4 or ROA6"); - - if (table->addr_type != (net->type == NET_IP4 ? NET_ROA4 : NET_ROA6)) - RESULT(T_ENUM_ROA, i, ROA_UNKNOWN); /* Prefix and table type mismatch */ - else - RESULT(T_ENUM_ROA, i, [[ net_roa_check(table, net, as) ]]); - } - - INST(FI_ROA_CHECK_EXPLICIT, 2, 1) { /* ROA Check */ + INST(FI_ROA_CHECK, 2, 1) { /* ROA Check */ NEVER_CONSTANT; ARG(1, T_NET); ARG(2, T_INT); diff --cc sysdep/unix/log.c index 0c89ebd65,53122aee3..81558d0a2 --- a/sysdep/unix/log.c +++ b/sysdep/unix/log.c @@@ -173,46 -152,49 +173,46 @@@ log_rotate(struct log_channel *lc * in log(), so it should be written like *L_INFO. */ void -log_commit(int class, buffer *buf) +log_commit(log_buffer *buf) { - struct log_config *l; - - if (buf->pos == buf->end) - strcpy(buf->end - 100, " ... "); - - log_lock(); - WALK_LIST(l, *current_log_list) + if (buf->buf.pos == buf->buf.end) +#define TOO_LONG " ... " + memcpy(buf->buf.end - sizeof TOO_LONG, TOO_LONG, sizeof TOO_LONG); +#undef TOO_LONG + + for ( + struct log_channel *l = atomic_load_explicit(&global_logs, memory_order_acquire); + l; + l = atomic_load_explicit(&l->next, memory_order_acquire) + ) { - if (!(l->mask & (1 << class))) + uint mask = atomic_load_explicit(&l->mask, memory_order_acquire); + if (!(mask & (1 << buf->class))) continue; - if (l->fh) + + struct rfile *rf = atomic_load_explicit(&l->rf, memory_order_acquire); + if (rf && buf->tm_pos) { - if (l->terminal_flag) - fputs("bird: ", l->fh); - else + *buf->buf.pos = '\n'; + byte *begin = l->terminal ? buf->buf.start : buf->tm_pos; + off_t msg_len = buf->buf.pos - begin + 1; + do { - if (rf_write(rf, buf->tm_pos, msg_len)) ++ if (rf_write(rf, begin, msg_len)) + break; + + log_lock(); + rf = atomic_load_explicit(&l->rf, memory_order_acquire); - if (rf_write(rf, buf->tm_pos, msg_len)) ++ if (rf_write(rf, begin, msg_len)) { - byte tbuf[TM_DATETIME_BUFFER_SIZE]; - const char *fmt = config ? config->tf_log.fmt1 : "%F %T.%3f"; - if (!tm_format_real_time(tbuf, sizeof(tbuf), fmt, current_real_time())) - strcpy(tbuf, ""); - - if (l->limit) - { - off_t msg_len = strlen(tbuf) + strlen(class_names[class]) + - (buf->pos - buf->start) + 5; - - if (l->pos < 0) - l->pos = log_size(l); - - if (l->pos + msg_len > l->limit) - if (log_rotate(l) < 0) - continue; + log_unlock(); + break; + } - l->pos += msg_len; - } + log_rotate(l); + log_unlock(); - fprintf(l->fh, "%s <%s> ", tbuf, class_names[class]); - } - fputs(buf->start, l->fh); - fputc('\n', l->fh); - fflush(l->fh); + rf = atomic_load_explicit(&l->rf, memory_order_relaxed); - } while (!rf_write(rf, buf->tm_pos, msg_len)); ++ } while (!rf_write(rf, begin, msg_len)); } #ifdef HAVE_SYSLOG_H else @@@ -228,34 -212,6 +228,36 @@@ int buffer_vprint(buffer *buf, const char *fmt, va_list args); +void +log_prepare(log_buffer *buf, int class) +{ + buf->buf.start = buf->buf.pos = buf->block; + buf->buf.end = buf->block + sizeof buf->block; + + int lf = atomic_load_explicit(&logging_flags, memory_order_acquire); + if (lf & LOGGING_TO_TERMINAL) + buffer_puts(&buf->buf, "bird: "); + + if (lf & LOGGING_TO_FILE) + { + const char *fmt = config ? config->tf_log.fmt1 : "%F %T.%3f"; + + buf->tm_pos = buf->buf.pos; + int t = tm_format_real_time(buf->buf.pos, buf->buf.end - buf->buf.pos, fmt, current_real_time()); + if (t) + buf->buf.pos += t; + else + buffer_puts(&buf->buf, "