From: Maria Matejka Date: Sat, 28 Oct 2023 22:50:38 +0000 (+0200) Subject: Merge commit 'a3dc2645' into thread-next X-Git-Tag: v3.0.0~372 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=de8288c67987f2a8f1312abd48733999b92625ab;p=thirdparty%2Fbird.git Merge commit 'a3dc2645' into thread-next --- de8288c67987f2a8f1312abd48733999b92625ab diff --cc conf/confbase.Y index d86c2ef57,7b368fc6d..f841c9742 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@@ -128,8 -125,7 +128,8 @@@ CF_DECL %nonassoc PREFIX_DUMMY %left AND OR - %nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA PO PC + %nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA IMP PO PC +%left '|' '&' %left '+' '-' %left '*' '/' '%' %left '!' diff --cc filter/config.Y index 1922955ff,a87fb0e5f..76e804361 --- a/filter/config.Y +++ b/filter/config.Y @@@ -374,7 -357,8 +374,7 @@@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UN %nonassoc ELSE %type cmds_int cmd_prep - %type term term_bs cmd cmd_var cmds cmds_scoped constant constructor var var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont + %type term term_bs cmd cmd_var cmds cmds_scoped constant constructor var var_list var_list_r 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 @@@ -566,19 -535,13 +571,14 @@@ function_body ; conf: function_def ; - maybe_type: - /* EMPTY */ { $$ = T_VOID; } - | type { $$ = $1; } - ; function_def: - 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" ); */ + FUNCTION symbol { + DBG( "Beginning of function %s\n", $2->name ); + this_function = cf_define_symbol(new_config, $2, SYM_FUNCTION, function, NULL); + cf_enter_filters(); cf_push_scope(new_config, this_function); - } function_args { + } function_args function_type { /* Make dummy f_line for storing function prototype */ struct f_line *dummy = cfg_allocz(sizeof(struct f_line)); this_function->function = dummy; @@@ -598,9 -561,8 +598,9 @@@ $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; + $2->function = $7; cf_pop_scope(new_config); + cf_exit_filters(); } ; @@@ -828,13 -790,30 +828,30 @@@ constructor ; - /* This generates the function_call variable list backwards. */ - var_list: /* EMPTY */ { $$ = NULL; } + /* This generates the function_call variable list backwards */ + var_list_r: + /* EMPTY */ { $$ = NULL; } | term { $$ = $1; } - | var_list ',' term { $$ = $3; $$->next = $1; } + | var_list_r ',' term { $$ = $3; $$->next = $1; } + ; + + var_list: var_list_r + { + $$ = NULL; + + /* Revert the var_list_r */ + while ($1) { + struct f_inst *tmp = $1; + $1 = $1->next; + + tmp->next = $$; + $$ = tmp; + } + } + ; function_call: - symbol_known '(' var_list ')' + CF_SYM_KNOWN '(' var_list ')' { if ($1->class != SYM_FUNCTION) cf_error("You can't call something which is not a function. Really."); @@@ -921,28 -893,22 +928,32 @@@ term | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); } - | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); } - | term_dot_method - | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, val_empty(T_PATH)); } - | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, val_empty(T_CLIST)); } - | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, val_empty(T_ECLIST)); } - | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, val_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); } + -| PREPEND '(' term ',' term ')' { $$ = f_dispatch_method_x("prepend", $3->type, $3, $5); } - | ADD '(' term ',' term ')' { $$ = f_dispatch_method_x("add", $3->type, $3, $5); } - | DELETE '(' term ',' term ')' { $$ = f_dispatch_method_x("delete", $3->type, $3, $5); } - | FILTER '(' term ',' term ')' { $$ = f_dispatch_method_x("filter", $3->type, $3, $5); } ++ | PREPEND '(' term ',' term ')' { ++ $$ = f_dispatch_method_x("prepend", $3->type, $3, $5); ++ cf_warn("prepend(x,y) function is deprecated, please use x.prepend(y)"); ++ } + | ADD '(' term ',' term ')' { + $$ = f_dispatch_method_x("add", $3->type, $3, $5); + cf_warn("add(x,y) function is deprecated, please use x.add(y)"); + } + | DELETE '(' term ',' term ')' { + $$ = f_dispatch_method_x("delete", $3->type, $3, $5); + cf_warn("delete(x,y) function is deprecated, please use x.delete(y)"); + } + | FILTER '(' term ',' term ')' { + $$ = f_dispatch_method_x("filter", $3->type, $3, $5); + 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); } @@@ -1032,20 -999,16 +1043,20 @@@ cmd cf_error( "This static attribute is read-only."); $$ = f_new_inst(FI_RTA_SET, $3, $1); } - | UNSET '(' dynamic_attr ')' ';' { - $$ = f_new_inst(FI_EA_UNSET, $3); + | UNSET '(' CF_SYM_KNOWN ')' ';' { + if ($3->class != SYM_ATTRIBUTE) + cf_error("Can't unset %s", $3->name); + if ($3->attribute->readonly) + cf_error("Attribute %s is read-only", $3->attribute->name); + $$ = f_new_inst(FI_EA_UNSET, $3->attribute); } - | break_command var_list ';' { + | break_command var_list_r ';' { $$ = f_print($2, !!$2, $1); } - | PRINT var_list ';' { + | PRINT var_list_r ';' { $$ = f_print($2, 1, F_NOP); } - | PRINTN var_list ';' { + | PRINTN var_list_r ';' { $$ = f_print($2, 0, F_NOP); } | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); } diff --cc filter/data.c index d700f7d2b,deca00e0a..610af8a21 --- a/filter/data.c +++ b/filter/data.c @@@ -27,9 -27,8 +27,11 @@@ static const char * const f_type_str[] = { [T_VOID] = "void", + [T_NONE] = "none", + + [T_OPAQUE] = "opaque byte string", + [T_IFACE] = "interface", + [T_INT] = "int", [T_BOOL] = "bool", [T_PAIR] = "pair", @@@ -57,19 -56,22 +59,21 @@@ [T_LC] = "lc", [T_LCLIST] = "lclist", [T_RD] = "rd", + + [T_SET] = "set", + [T_PREFIX_SET] = "prefix set", }; ++STATIC_ASSERT((1 << (8 * sizeof(btype))) == ARRAY_SIZE(f_type_str)); ++ const char * -f_type_name(enum f_type t) +f_type_name(btype t) { - return (t < ARRAY_SIZE(f_type_str)) ? (f_type_str[t] ?: "?") : "?"; - if (t < ARRAY_SIZE(f_type_str)) - return f_type_str[t] ?: "?"; - - if ((t == T_SET) || (t == T_PREFIX_SET)) - return "set"; - - return "?"; ++ return f_type_str[t] ?: "?"; } -enum f_type -f_type_element_type(enum f_type t) +btype +f_type_element_type(btype t) { switch(t) { case T_PATH: return T_INT; diff --cc filter/decl.m4 index 63670932d,57bf94546..2cb09f28c --- a/filter/decl.m4 +++ b/filter/decl.m4 @@@ -573,8 -573,8 +574,8 @@@ fi_constant(struct f_inst *what, struc return what; } - static int - f_const_promotion(struct f_inst *arg, btype want) + int -f_const_promotion_(struct f_inst *arg, enum f_type want, int update) ++f_const_promotion_(struct f_inst *arg, btype want, int update) { if (arg->fi_code != FI_CONSTANT) return 0; diff --cc filter/f-inst.h index fa1fdbde6,2bde6378c..a476c998e --- a/filter/f-inst.h +++ b/filter/f-inst.h @@@ -36,6 -36,16 +36,16 @@@ const char *f_instruction_name_(enum f_ static inline const char *f_instruction_name(enum f_instruction_code fi) { return f_instruction_name_(fi) + 3; } + -int f_const_promotion_(struct f_inst *arg, enum f_type want, int update); ++int f_const_promotion_(struct f_inst *arg, enum btype want, int update); + -static inline int f_const_promotion(struct f_inst *arg, enum f_type want) ++static inline int f_const_promotion(struct f_inst *arg, enum btype want) + { return f_const_promotion_(arg, want, 1); } + -static inline int f_try_const_promotion(struct f_inst *arg, enum f_type want) ++static inline int f_try_const_promotion(struct f_inst *arg, enum btype want) + { return f_const_promotion_(arg, want, 0); } + + struct f_arg { struct symbol *arg; struct f_arg *next; @@@ -96,15 -106,17 +106,15 @@@ void f_add_lines(const struct f_line_it struct filter *f_new_where(struct f_inst *); - struct f_inst *f_dispatch_method(struct symbol *sym, struct f_inst *obj, struct f_inst *args); + struct f_inst *f_dispatch_method(struct symbol *sym, struct f_inst *obj, struct f_inst *args, int skip); -struct f_inst *f_dispatch_method_x(const char *name, enum f_type t, struct f_inst *obj, struct f_inst *args); +struct f_inst *f_dispatch_method_x(const char *name, enum btype t, struct f_inst *obj, struct f_inst *args); struct f_inst *f_for_cycle(struct symbol *var, struct f_inst *term, struct f_inst *block); +struct f_inst *f_implicit_roa_check(struct rtable_config *tab); struct f_inst *f_print(struct f_inst *vars, int flush, enum filter_return fret); -static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */ -{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */ -static inline struct f_dynamic_attr f_new_dynamic_attr_bit(u8 bit, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */ -{ return (struct f_dynamic_attr) { .type = EAF_TYPE_BITFIELD, .bit = bit, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */ -static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly) -{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; } +static inline struct f_static_attr f_new_static_attr(btype type, int code, int 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); /* Hook for call bt_assert() function in configuration */ extern void (*bt_assert_hook)(int result, const struct f_line_item *assert); diff --cc filter/f-util.c index 7ae304d60,d589927a1..e014b2248 --- a/filter/f-util.c +++ b/filter/f-util.c @@@ -87,9 -162,9 +162,9 @@@ f_for_cycle(struct symbol *var, struct /* Static type check */ if (term->type == T_VOID) - cf_error("Couldn't infer the type of FOR expression, please assign it to a variable."); + cf_error("Cannot infer type of FOR expression, please assign it to a variable"); - enum f_type el_type = f_type_element_type(term->type); + enum btype el_type = f_type_element_type(term->type); struct sym_scope *scope = el_type ? f_type_method_scope(term->type) : NULL; struct symbol *ms = scope ? cf_find_symbol_scope(scope, "!for_next") : NULL; @@@ -113,28 -188,6 +188,28 @@@ return ms->method->new_inst(term, loop_start); } +struct f_inst * +f_implicit_roa_check(struct rtable_config *tab) +{ + const struct ea_class *def = ea_class_find("bgp_path"); + if (!def) + bug("Couldn't find BGP AS Path attribute definition."); + + struct f_inst *path_getter = f_new_inst(FI_EA_GET, def); + struct sym_scope *scope = f_type_method_scope(path_getter->type); + struct symbol *ms = scope ? cf_find_symbol_scope(scope, "last") : NULL; + + if (!ms) + bug("Couldn't find the \"last\" method for AS Path."); + + 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_dispatch_method(ms, path_getter, NULL), ++ ms->method->new_inst(path_getter, NULL), + tab); +} + struct f_inst * f_print(struct f_inst *vars, int flush, enum filter_return fret) { diff --cc lib/type.h index 232e7aef2,000000000..019530878 mode 100644,000000..100644 --- a/lib/type.h +++ b/lib/type.h @@@ -1,114 -1,0 +1,115 @@@ +/* + * BIRD Internet Routing Daemon -- Internal Data Types + * + * (c) 2022 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_TYPE_H_ +#define _BIRD_TYPE_H_ + +#include "lib/birdlib.h" +#include "lib/attrs.h" + +union bval { +#define BVAL_ITEMS \ + struct { \ + u32 data; /* Integer type inherited from eattrs */ \ + PADDING(data, 0, 4); /* Must be padded on 64-bits */ \ + }; \ + struct { \ + u32 i; /* Integer type inherited from filters */ \ + PADDING(i, 0, 4); /* Must be padded on 64-bits */ \ + }; \ + const struct adata *ptr; /* Generic attribute data inherited from eattrs */ \ + const struct adata *ad; /* Generic attribute data inherited from filters */ \ + + BVAL_ITEMS; +}; + +union bval_long { + union bval bval; /* For direct assignments */ + BVAL_ITEMS; /* For item-wise access */ + + 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 f_path_mask *path_mask; + struct f_path_mask_item pmi; +}; + + +/* Internal types */ +enum btype { +/* Nothing. Simply nothing. */ + T_VOID = 0, ++ T_NONE = 0xff, + +/* Something but inaccessible. */ + T_OPAQUE = 0x02, /* Opaque byte string (not filterable) */ + T_IFACE = 0x0c, /* Pointer to an interface (inside adata) */ + T_NEXTHOP_LIST = 0x2c, /* The whole nexthop block */ + T_HOSTENTRY = 0x2e, /* Hostentry with possible MPLS labels */ + +/* Types shared with eattrs */ + T_INT = 0x01, /* 32-bit unsigned integer number */ + T_IP = 0x04, /* IP address */ + T_QUAD = 0x05, /* Router ID (IPv4 address) */ + T_PATH = 0x06, /* BGP AS path (encoding per RFC 1771:4.3) */ + T_CLIST = 0x0a, /* Set of u32's (e.g., a community list) */ + T_ECLIST = 0x0e, /* Set of pairs of u32's - ext. community list */ + T_LCLIST = 0x08, /* Set of triplets of u32's - large community list */ + + T_ENUM_BGP_ORIGIN = 0x11, /* BGP Origin enum */ + T_ENUM_RA_PREFERENCE = 0x13, /* RA Preference enum */ + T_ENUM_FLOWSPEC_VALID = 0x15, /* Flowspec validation result */ + +#define EAF_TYPE__MAX 0x1f +#define EAF_EMBEDDED 0x01 /* Data stored in eattr.u.data (part of type spec) */ + /* Otherwise, attribute data is adata */ + +/* Other user visible types which fit in int */ + T_BOOL = 0xa0, + T_PAIR = 0xa4, /* Notice that pair is stored as integer: first << 16 | second */ + +/* Put enumerational types in 0x20..0x3f range */ + T_ENUM_LO = 0x10, + T_ENUM_HI = 0x3f, + + T_ENUM_RTS = 0x31, + T_ENUM_SCOPE = 0x33, + T_ENUM_RTD = 0x37, + T_ENUM_ROA = 0x39, + T_ENUM_NETTYPE = 0x3b, + T_ENUM_AF = 0x3d, + +/* new enums go here */ + +#define T_ENUM T_ENUM_LO ... T_ENUM_HI + +/* Bigger ones */ + T_NET = 0xb0, + T_STRING = 0xb4, + T_PATH_MASK = 0xb8, /* mask for BGP path */ + T_EC = 0xbc, /* Extended community value, u64 */ + T_LC = 0xc0, /* Large community value, lcomm */ + T_RD = 0xc4, /* Route distinguisher for VPN addresses */ + T_PATH_MASK_ITEM = 0xc8, /* Path mask item for path mask constructors */ + T_BYTESTRING = 0xcc, + + T_SET = 0x80, + T_PREFIX_SET = 0x84, +} PACKED; + +typedef enum btype btype; + +STATIC_ASSERT(sizeof(btype) == sizeof(byte)); + + +#endif