From de70474fed139f9acb4ed3f8e925d12de4edcdd0 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Sun, 29 Oct 2023 19:53:09 +0100 Subject: [PATCH] Filter: adding explicit route type This is a split-commit of the neighboring aggregator branch with a bit improved lvalue handling, to have easier merge into v3. --- conf/confbase.Y | 2 +- filter/config.Y | 91 +++++++++++++++++++++---------------------------- filter/data.c | 21 ++++++++++++ filter/data.h | 7 ++++ filter/f-inst.c | 23 +++++++++---- nest/route.h | 2 ++ nest/rt-attr.c | 2 +- nest/rt-table.c | 7 ++-- 8 files changed, 92 insertions(+), 63 deletions(-) diff --git a/conf/confbase.Y b/conf/confbase.Y index 0364bc6e1..cdf1f0187 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -433,7 +433,7 @@ bytestring_text: ; bytestring_expr: - symbol_value + lvalue { $$ = f_lval_getter(&$1); } | term_bs | '(' term ')' { $$ = $2; } ; diff --git a/filter/config.Y b/filter/config.Y index dfabddf7b..4e1f6359f 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -38,15 +38,15 @@ static inline void f_method_call_start(struct f_inst *object) cf_error("Too many nested method calls"); struct sym_scope *scope = f_type_method_scope(object->type); - if (!scope) + if (!scope && object->type != T_ROUTE) cf_error("No methods defined for type %s", f_type_name(object->type)); FM = (struct f_method_scope) { .object = object, .main = new_config->current_scope, .scope = { - .next = NULL, - .hash = scope->hash, + .next = scope ? global_root_scope : NULL, + .hash = scope ? scope->hash : global_root_scope->hash, .active = 1, .block = 1, .readonly = 1, @@ -244,6 +244,7 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3) return t; } + /* * Remove all new lines and doubled whitespaces * and convert all tabulators to spaces @@ -302,9 +303,10 @@ static struct f_inst * f_lval_getter(struct f_lval *lval) { switch (lval->type) { + case F_LVAL_CONSTANT: return f_new_inst(FI_CONSTANT, *(lval->sym->val)); case F_LVAL_VARIABLE: return f_new_inst(FI_VAR_GET, lval->sym); - case F_LVAL_SA: return f_new_inst(FI_RTA_GET, lval->sa); - case F_LVAL_EA: return f_new_inst(FI_EA_GET, lval->da); + case F_LVAL_SA: return f_new_inst(FI_RTA_GET, lval->rte, lval->sa); + case F_LVAL_EA: return f_new_inst(FI_EA_GET, lval->rte, lval->da); default: bug("Unknown lval type"); } } @@ -313,8 +315,13 @@ static struct f_inst * f_lval_setter(struct f_lval *lval, struct f_inst *expr) { switch (lval->type) { + case F_LVAL_CONSTANT: cf_error("Constant %s is read-only", lval->sym->name); case F_LVAL_VARIABLE: return f_new_inst(FI_VAR_SET, expr, lval->sym); - case F_LVAL_SA: return f_new_inst(FI_RTA_SET, expr, lval->sa); + case F_LVAL_SA: + if (lval->sa.readonly) + cf_error( "This static attribute is read-only."); + return f_new_inst(FI_RTA_SET, expr, lval->sa); + case F_LVAL_EA: return f_new_inst(FI_EA_SET, expr, lval->da); default: bug("Unknown lval type"); } @@ -357,7 +364,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %nonassoc ELSE %type cmds_int cmd_prep -%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 term term_bs cmd cmd_var cmds cmds_scoped constant constructor var var_list var_list_r function_call bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont %type dynamic_attr %type static_attr %type filter where_filter @@ -447,6 +454,7 @@ type: | CLIST { $$ = T_CLIST; } | ECLIST { $$ = T_ECLIST; } | LCLIST { $$ = T_LCLIST; } + | ROUTE { $$ = T_ROUTE; } | type SET { switch ($1) { case T_INT: @@ -740,7 +748,7 @@ switch_body: /* EMPTY */ { $$ = NULL; } ; bgp_path_expr: - symbol_value { $$ = $1; } + lvalue { $$ = f_lval_getter(&$1); } | '(' term ')' { $$ = $2; } ; @@ -822,23 +830,6 @@ function_call: } ; -symbol_value: symbol_known - { - switch ($1->class) { - case SYM_CONSTANT_RANGE: - $$ = f_new_inst(FI_CONSTANT, *($1->val)); - break; - case SYM_VARIABLE_RANGE: - $$ = f_new_inst(FI_VAR_GET, $1); - break; - case SYM_ATTRIBUTE: - $$ = f_new_inst(FI_EA_GET, *$1->attribute); - break; - default: - cf_error("Can't get value of symbol %s", $1->name); - } - } - ; static_attr: FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); } @@ -866,6 +857,16 @@ method_name_cont: } '(' var_list ')' { $$ = f_dispatch_method($1, FM.object, $4, 1); } + | static_attr { + if (FM.object->type != T_ROUTE) + cf_error("Getting a route attribute from %s, need a route", f_type_name(FM.object->type)); + $$ = f_new_inst(FI_RTA_GET, FM.object, $1); + } + | dynamic_attr { + if (FM.object->type != T_ROUTE) + cf_error("Getting a route attribute from %s, need a route", f_type_name(FM.object->type)); + $$ = f_new_inst(FI_EA_GET, FM.object, $1); + } ; term: @@ -887,13 +888,10 @@ term: | '!' term { $$ = f_new_inst(FI_NOT, $2); } | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); } - | symbol_value { $$ = $1; } | constant { $$ = $1; } | constructor { $$ = $1; } - | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); } - - | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); } + | lvalue { $$ = f_lval_getter(&$1); } | term_dot_method @@ -902,7 +900,7 @@ term: | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, val_empty(T_ECLIST)); } | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, val_empty(T_LCLIST)); } -| PREPEND '(' term ',' term ')' { $$ = f_dispatch_method_x("prepend", $3->type, $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); } @@ -963,17 +961,8 @@ cmd: cf_pop_block_scope(new_config); $$ = f_for_cycle($3, $6, $9); } - | symbol_known '=' term ';' { - switch ($1->class) { - case SYM_VARIABLE_RANGE: - $$ = f_new_inst(FI_VAR_SET, $3, $1); - break; - case SYM_ATTRIBUTE: - $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute); - break; - default: - cf_error("Can't assign to symbol %s", $1->name); - } + | lvalue '=' term ';' { + $$ = f_lval_setter(&$1, $3); } | RETURN term ';' { DBG( "Ook, we'll return the value\n" ); @@ -991,14 +980,6 @@ cmd: $$ = 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."); - $$ = f_new_inst(FI_RTA_SET, $3, $1); - } | UNSET '(' dynamic_attr ')' ';' { $$ = f_new_inst(FI_EA_UNSET, $3); } @@ -1043,17 +1024,21 @@ lvalue: CF_SYM_KNOWN { switch ($1->class) { + case SYM_CONSTANT_RANGE: + $$ = (struct f_lval) { .type = F_LVAL_CONSTANT, .sym = $1, }; + break; case SYM_VARIABLE_RANGE: - $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; + $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1, }; break; case SYM_ATTRIBUTE: - $$ = (struct f_lval) { .type = F_LVAL_EA, .da = *($1->attribute) }; + $$ = (struct f_lval) { .type = F_LVAL_EA, .da = *($1->attribute), .rte = f_new_inst(FI_CURRENT_ROUTE), }; break; default: cf_error("Variable name or custom attribute name required"); } } - | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; } - | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; }; + | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1, .rte = f_new_inst(FI_CURRENT_ROUTE), }; } + | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1, .rte = f_new_inst(FI_CURRENT_ROUTE), }; } + ; CF_END diff --git a/filter/data.c b/filter/data.c index 89b75e565..cb52b499c 100644 --- a/filter/data.c +++ b/filter/data.c @@ -56,6 +56,8 @@ static const char * const f_type_str[] = { [T_LC] = "lc", [T_LCLIST] = "lclist", [T_RD] = "rd", + + [T_ROUTE] = "route", }; const char * @@ -206,6 +208,7 @@ val_compare(const struct f_val *v1, const struct f_val *v2) return net_compare(v1->val.net, v2->val.net); case T_STRING: return strcmp(v1->val.s, v2->val.s); + case T_ROUTE: default: return F_CMP_ERROR; } @@ -296,6 +299,8 @@ val_same(const struct f_val *v1, const struct f_val *v2) return same_tree(v1->val.t, v2->val.t); case T_PREFIX_SET: return trie_same(v1->val.ti, v2->val.ti); + case T_ROUTE: + return rte_same(v1->val.rte, v2->val.rte); default: bug("Invalid type in val_same(): %x", v1->type); } @@ -569,6 +574,21 @@ val_in_range(const struct f_val *v1, const struct f_val *v2) return F_CMP_ERROR; } +/* + * rte_format - format route information + */ +static void +rte_format(const struct rte *rte, buffer *buf) +{ + if (rte) + buffer_print(buf, "Route [%d] to %N from %s.%s via %s", + rte->src->global_id, rte->net->n.addr, + rte->sender->proto->name, rte->sender->name, + rte->src->proto->name); + else + buffer_puts(buf, "[No route]"); +} + /* * val_format - format filter value */ @@ -598,6 +618,7 @@ val_format(const struct f_val *v, buffer *buf) case T_ECLIST: ec_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return; case T_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return; case T_PATH_MASK: pm_format(v->val.path_mask, buf); return; + case T_ROUTE: rte_format(v->val.rte, buf); return; default: buffer_print(buf, "[unknown type %x]", v->type); return; } } diff --git a/filter/data.h b/filter/data.h index 3430455a5..620a80bf7 100644 --- a/filter/data.h +++ b/filter/data.h @@ -62,6 +62,7 @@ enum f_type { T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */ T_BYTESTRING = 0x2c, + T_ROUTE = 0x78, T_SET = 0x80, T_PREFIX_SET = 0x81, } PACKED; @@ -90,6 +91,10 @@ struct f_val { const struct adata *ad; const struct f_path_mask *path_mask; struct f_path_mask_item pmi; + struct { + rte *rte; + ea_list *eattrs; + }; } val; }; @@ -127,6 +132,7 @@ struct f_static_attr { /* Filter l-value type */ enum f_lval_type { + F_LVAL_CONSTANT, F_LVAL_VARIABLE, F_LVAL_PREFERENCE, F_LVAL_SA, @@ -136,6 +142,7 @@ enum f_lval_type { /* Filter l-value */ struct f_lval { enum f_lval_type type; + struct f_inst *rte; union { struct symbol *sym; struct f_dynamic_attr da; diff --git a/filter/f-inst.c b/filter/f-inst.c index a7bec81ed..76ec272de 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -654,11 +654,20 @@ } } - INST(FI_RTA_GET, 0, 1) { + INST(FI_CURRENT_ROUTE, 0, 1) { + NEVER_CONSTANT; + ACCESS_EATTRS; + RESULT_TYPE(T_ROUTE); + RESULT_VAL([[(struct f_val) { .type = T_ROUTE, .val.rte = *fs->rte, .val.eattrs = *fs->eattrs, }]]); + } + + INST(FI_RTA_GET, 1, 1) { { - STATIC_ATTR; ACCESS_RTE; - struct rta *rta = (*fs->rte)->attrs; + ARG(1, T_ROUTE); + STATIC_ATTR; + + struct rta *rta = v1.val.rte->attrs; switch (sa.sa_code) { @@ -797,13 +806,15 @@ } } - INST(FI_EA_GET, 0, 1) { /* Access to extended attributes */ - DYNAMIC_ATTR; + INST(FI_EA_GET, 1, 1) { /* Access to extended attributes */ ACCESS_RTE; ACCESS_EATTRS; + ARG(1, T_ROUTE); + DYNAMIC_ATTR; RESULT_TYPE(da.f_type); { - eattr *e = ea_find(*fs->eattrs, da.ea_code); + struct ea_list *eal = v1.val.eattrs; + eattr *e = ea_find(eal, da.ea_code); if (!e) { RESULT_VAL(val_empty(da.f_type)); diff --git a/nest/route.h b/nest/route.h index 7aec71179..42da5b198 100644 --- a/nest/route.h +++ b/nest/route.h @@ -326,6 +326,8 @@ void rt_refresh_begin(rtable *t, struct channel *c); void rt_refresh_end(rtable *t, struct channel *c); void rt_modify_stale(rtable *t, struct channel *c); void rt_schedule_prune(rtable *t); +int rte_same(rte *, rte *); +int rta_same(struct rta *, struct rta *); void rte_dump(rte *); void rte_free(rte *); rte *rte_do_cow(rte *); diff --git a/nest/rt-attr.c b/nest/rt-attr.c index d793c72e1..69ef45424 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -1126,7 +1126,7 @@ rta_hash(rta *a) return mem_hash_value(&h) ^ nexthop_hash(&(a->nh)) ^ ea_hash(a->eattrs); } -static inline int +int rta_same(rta *x, rta *y) { return (x->source == y->source && diff --git a/nest/rt-table.c b/nest/rt-table.c index 742e2f05b..206fc6ef3 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -1206,12 +1206,15 @@ rte_free_quick(rte *e) sl_free(e); } -static int +int rte_same(rte *x, rte *y) { /* rte.flags / rte.pflags are not checked, as they are internal to rtable */ return - x->attrs == y->attrs && + ( + (x->attrs == y->attrs) || + ((!x->attrs->cached || !y->attrs->cached) && rta_same(x->attrs, y->attrs)) + ) && x->src == y->src && rte_is_filtered(x) == rte_is_filtered(y); } -- 2.47.2