0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-10-18 09:58:43 +00:00

Filter: Fixes and improvements related to case/sets

Unify grammar for set_atom and switch_atom to avoid inconsistencies
between them. Fix errors in documentation related to case statement
and set type. Change 'vpnrd' to 'rd' to be consistent with the filter
language.

Thanks to Mikhail Mayorov for bugreport.
This commit is contained in:
Ondrej Zajicek 2024-10-08 19:34:51 +02:00
parent 163ab3130f
commit 39e75b879b
3 changed files with 37 additions and 29 deletions

View File

@ -1650,7 +1650,7 @@ in the foot).
Route Distinguisher (<rfc id="4364">). They support the same special Route Distinguisher (<rfc id="4364">). They support the same special
operators as IP prefixes, and also <cf/.rd/ which extracts the Route operators as IP prefixes, and also <cf/.rd/ which extracts the Route
Distinguisher. Their literals are written Distinguisher. Their literals are written
as <cf><m/vpnrd/ <m/ipprefix/</cf> as <cf><m/rd/ <m/ipprefix/</cf>
<cf/NET_ROA4/ and <cf/NET_ROA6/ prefixes hold an IP prefix range <cf/NET_ROA4/ and <cf/NET_ROA6/ prefixes hold an IP prefix range
together with an ASN. They support the same special operators as IP together with an ASN. They support the same special operators as IP
@ -1665,9 +1665,9 @@ in the foot).
<cf/NET_MPLS/ holds a single MPLS label and its handling is currently <cf/NET_MPLS/ holds a single MPLS label and its handling is currently
not implemented. not implemented.
<tag><label id="type-vpnrd">vpnrd</tag> <tag><label id="type-rd"><label id="type-vpnrd">rd</tag>
This is a route distinguisher according to <rfc id="4364">. There are This is a route distinguisher according to <rfc id="4364">. There are
three kinds of RD's: <cf><m/asn/:<m/32bit int/</cf>, <cf><m/asn4/:<m/16bit int/</cf> three kinds of RDs: <cf><m/asn/:<m/32bit int/</cf>, <cf><m/asn4/:<m/16bit int/</cf>
and <cf><m/IPv4 address/:<m/32bit int/</cf> and <cf><m/IPv4 address/:<m/32bit int/</cf>
<tag><label id="type-ec">ec</tag> <tag><label id="type-ec">ec</tag>
@ -1694,9 +1694,9 @@ in the foot).
to extract corresponding components of LCs: to extract corresponding components of LCs:
<cf>(<m/asn/, <m/data1/, <m/data2/)</cf>. <cf>(<m/asn/, <m/data1/, <m/data2/)</cf>.
<tag><label id="type-set">int|pair|quad|ip|prefix|ec|lc|enum set</tag> <tag><label id="type-set">int|pair|quad|ip|prefix|ec|lc|rd|enum set</tag>
Filters recognize four types of sets. Sets are similar to strings: you Filters recognize several types of sets. Sets are similar to strings: you
can pass them around but you can't modify them. Literals of type <cf>int can pass them around but you cannot modify them. Literals of type <cf>int
set</cf> look like <cf> [ 1, 2, 5..7 ]</cf>. As you can see, both simple set</cf> look like <cf> [ 1, 2, 5..7 ]</cf>. As you can see, both simple
values and ranges are permitted in sets. values and ranges are permitted in sets.
@ -1719,9 +1719,11 @@ in the foot).
is valid, while <cf/(10, *, 20..30)/ or <cf/(10, 20..30, 40)/ is not is valid, while <cf/(10, *, 20..30)/ or <cf/(10, 20..30, 40)/ is not
valid. valid.
You can also use expressions for int, pair, EC and LC set values. You can also use named constants or compound expressions for non-prefix
However, it must be possible to evaluate these expressions before daemon set values. However, it must be possible to evaluate these expressions
boots. So you can use only constants inside them. E.g. before daemon boots. So you can use only constants inside them. Also,
in case of compound expressions, they require parentheses around them.
E.g.
<code> <code>
define one=1; define one=1;
@ -1730,7 +1732,7 @@ in the foot).
pair set ps; pair set ps;
ec set es; ec set es;
odds = [ one, 2+1, 6-one, 2*2*2-1, 9, 11 ]; odds = [ one, (2+1), (6-one), (2*2*2-1), 9, 11 ];
ps = [ (1,one+one), (3,4)..(4,8), (5,*), (6,3..6), (7..9,*) ]; ps = [ (1,one+one), (3,4)..(4,8), (5,*), (6,3..6), (7..9,*) ];
es = [ (rt, myas, 3*10), (rt, myas+one, 0..16*16*16-1), (ro, myas+2, *) ]; es = [ (rt, myas, 3*10), (rt, myas+one, 0..16*16*16-1), (ro, myas+2, *) ];
</code> </code>
@ -1943,13 +1945,16 @@ may be an existing one (when just name is used) or a locally defined (when type
and name is used). In both cases, it must have the same type as elements. and name is used). In both cases, it must have the same type as elements.
<p>The <cf>case</cf> is similar to case from Pascal. Syntax is <cf>case <p>The <cf>case</cf> is similar to case from Pascal. Syntax is <cf>case
<m/expr/ { else: | <m/num_or_prefix [ .. num_or_prefix]/: <m/statement/ ; [ <m/expr/ { else: | <m/set_body_expr/ /: <m/statement/ ; [... ] }</cf>.
... ] }</cf>. The expression after <cf>case</cf> can be of any type which can be
on the left side of the &tilde; operator and anything that could be a member of The expression after <cf>case</cf> can be of any type that could be a member of
a set is allowed before <cf/:/. Multiple commands are allowed without <cf/{}/ a set, while the <m/set_body_expr/ before <cf/:/ can be anything (constants,
grouping. If <cf><m/expr/</cf> matches one of the <cf/:/ clauses, statements intervals, expressions) that could be a part of a set literal. One exception is
between it and next <cf/:/ statement are executed. If <cf><m/expr/</cf> matches prefix type, which can be used in sets bud not in <cf/case/ structure. Multiple
neither of the <cf/:/ clauses, the statements after <cf/else:/ are executed. commands are allowed without <cf/{}/ grouping. If <cf><m/expr/</cf> matches one
of the <cf/:/ clauses, statements between it and next <cf/:/ statement are
executed. If <cf><m/expr/</cf> matches neither of the <cf/:/ clauses, the
statements after <cf/else:/ are executed.
<p>Here is example that uses <cf/if/ and <cf/case/ structures: <p>Here is example that uses <cf/if/ and <cf/case/ structures:
@ -4085,11 +4090,11 @@ could have up to 5 channels: <cf/ipv4/, <cf/ipv6/, <cf/vpn4/, <cf/vpn6/, and
<cf/mpls/. <cf/mpls/.
<p><descrip> <p><descrip>
<tag><label id="l3vpn-route-distinguisher">route distinguisher <m/vpnrd/</tag> <tag><label id="l3vpn-route-distinguisher">route distinguisher <m/rd/</tag>
The route distinguisher that is attached to routes in the export The route distinguisher that is attached to routes in the export
direction. Mandatory. direction. Mandatory.
<tag><label id="l3vpn-rd">rd <m/vpnrd/</tag> <tag><label id="l3vpn-rd">rd <m/rd/</tag>
A shorthand for the option <cf/route distinguisher/. A shorthand for the option <cf/route distinguisher/.
<tag><label id="l3vpn-import-target">import target <m/ec/|<m/ec-set/</tag> <tag><label id="l3vpn-import-target">import target <m/ec/|<m/ec-set/</tag>

View File

@ -390,7 +390,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%type <i32> cnum %type <i32> cnum
%type <e> pair_item ec_item lc_item set_item switch_item ec_items set_items switch_items switch_body %type <e> pair_item ec_item lc_item set_item switch_item ec_items set_items switch_items switch_body
%type <trie> fprefix_set %type <trie> fprefix_set
%type <v> set_atom switch_atom fipa %type <v> set_atom0 set_atom switch_atom fipa
%type <px> fprefix %type <px> fprefix
%type <t> get_cf_position %type <t> get_cf_position
%type <s> for_var %type <s> for_var
@ -636,27 +636,30 @@ fipa:
* as a function call in switch case cmds. * as a function call in switch case cmds.
*/ */
set_atom: set_atom0:
NUM { $$.type = T_INT; $$.val.i = $1; } NUM { $$.type = T_INT; $$.val.i = $1; }
| fipa { $$ = $1; } | fipa { $$ = $1; }
| VPN_RD { $$.type = T_RD; $$.val.ec = $1; } | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
| '(' term ')' { | '(' term ')' {
$$ = cf_eval($2, T_VOID); $$ = cf_eval($2, T_VOID);
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); if (!f_valid_set_type($$.type))
cf_error("Set-incompatible type (%s)", f_type_name($$.type));
} }
;
set_atom:
set_atom0
| symbol_known { | symbol_known {
cf_assert_symbol($1, SYM_CONSTANT); cf_assert_symbol($1, SYM_CONSTANT);
if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name); if (!f_valid_set_type(SYM_TYPE($1)))
cf_error("%s: Set-incompatible type (%s)", $1->name, f_type_name(SYM_TYPE($1)));
$$ = *$1->val; $$ = *$1->val;
} }
; ;
switch_atom: switch_atom:
NUM { $$.type = T_INT; $$.val.i = $1; } set_atom0
| '(' term ')' { $$ = cf_eval($2, T_INT); }
| fipa { $$ = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
; ;
cnum: cnum:
@ -749,7 +752,7 @@ fprefix_set:
; ;
switch_body: /* EMPTY */ { $$ = NULL; } switch_body: /* EMPTY */ { $$ = NULL; }
| switch_body switch_items ':' cmds_scoped { | switch_body switch_items ':' cmds_scoped {
/* Fill data fields */ /* Fill data fields */
struct f_tree *t; struct f_tree *t;
for (t = $2; t; t = t->left) for (t = $2; t; t = t->left)

View File

@ -138,7 +138,7 @@ function t_int()
} }
case four { case four {
4: bt_assert(true); (2+2): bt_assert(true);
else: bt_assert(false); else: bt_assert(false);
} }