Use RESET as predicate to set to empty value of dynamic attribute value in filters. Leave EMPTY for backwad compatibility, altought it not documented enywhere.
Uninline f_generate_empty() and refactor code in error path. Remove MATCH and CONTAINS from keyword list. --- doc/bird.sgml | 4 ++++ filter/config.Y | 35 ++++++++++++++++------------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 050acf3..d1d7860 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1053,6 +1053,8 @@ incompatible with each other (that is to prevent you from shooting in the foot). I.e., <cf/filter/ do the same as <cf/delete/ with inverted set <m/A/. + <cf><m/P/.reset</cf> deletes all ASNs from path <m/P/. + Statement <cf><m/P/ = prepend(<m/P/, <m/A/);</cf> can be shortened to <cf><m/P/.prepend(<m/A/);</cf> if <m/P/ is appropriate route attribute (for example <cf/bgp_path/). Similarly for <cf/delete/ and <cf/filter/. @@ -1098,6 +1100,8 @@ incompatible with each other (that is to prevent you from shooting in the foot). set <m/P/. <m/P/ may also be a clist, which works analogously; i.e., it works as clist intersection. + <cf><m/C/.reset</cf> deletes all items from clist <m/C/. + Statement <cf><m/C/ = add(<m/C/, <m/P/);</cf> can be shortened to <cf><m/C/.add(<m/P/);</cf> if <m/C/ is appropriate route attribute (for example <cf/bgp_community/). Similarly for diff --git a/filter/config.Y b/filter/config.Y index 04acfba..faa02f5 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -115,32 +115,36 @@ f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt) return t; } -static inline struct f_inst * +static struct f_inst * f_generate_empty(struct f_inst *dyn) -{ - struct f_inst *e = f_new_inst(); - e->code = 'E'; +{ + struct f_inst *e; + u16 aux; switch (dyn->aux & EAF_TYPE_MASK) { case EAF_TYPE_AS_PATH: - e->aux = T_PATH; + aux = T_PATH; break; case EAF_TYPE_INT_SET: - e->aux = T_CLIST; + aux = T_CLIST; break; case EAF_TYPE_EC_SET: - e->aux = T_ECLIST; + aux = T_ECLIST; break; default: cf_error("Can't empty that attribute"); } + e = f_new_inst(); + e->code = 'E'; + e->aux = aux; + dyn->code = P('e','S'); dyn->a1.p = e; + return dyn; } - static inline struct f_inst * f_generate_dpair(struct f_inst *t1, struct f_inst *t2) { @@ -265,10 +269,9 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, PREFERENCE, LEN, DEFINED, - ADD, DELETE, CONTAINS, RESET, - PREPEND, FIRST, LAST, MATCH, + ADD, DELETE, RESET, EMPTY, + PREPEND, FIRST, LAST, ROA_CHECK, - EMPTY, FILTER, WHERE, EVAL) %nonassoc THEN @@ -727,14 +730,6 @@ term: | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; } | term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; } -/* Communities */ -/* This causes one shift/reduce conflict - | rtadot dynamic_attr '.' ADD '(' term ')' { } - | rtadot dynamic_attr '.' DELETE '(' term ')' { } - | rtadot dynamic_attr '.' CONTAINS '(' term ')' { } - | rtadot dynamic_attr '.' RESET{ } -*/ - | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; } | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; } | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; } @@ -880,6 +875,8 @@ cmd: | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); } + | rtadot dynamic_attr '.' RESET ';' { $$ = f_generate_empty($2); } + | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); } | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); } | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); } -- 1.7.10.4