summaryrefslogtreecommitdiffstats
path: root/filter/config.Y
diff options
context:
space:
mode:
Diffstat (limited to 'filter/config.Y')
-rw-r--r--filter/config.Y238
1 files changed, 212 insertions, 26 deletions
diff --git a/filter/config.Y b/filter/config.Y
index 80e7428..3c5f18b 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -75,13 +75,185 @@ f_new_pair_set(int fa, int ta, int fb, int tb)
return lst;
}
+#define EC_ALL 0xFFFFFFFF
+
+static struct f_tree *
+f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
+{
+ u64 fm, to;
+
+ if (ipv4_used || (key >= 0x10000)) {
+ check_u16(vf);
+ if (vt == EC_ALL)
+ vt = 0xFFFF;
+ else
+ check_u16(vt);
+ }
+
+ if (kind == EC_GENERIC) {
+ fm = ec_generic(key, vf);
+ to = ec_generic(key, vt);
+ }
+ else if (ipv4_used) {
+ fm = ec_ip4(kind, key, vf);
+ to = ec_ip4(kind, key, vt);
+ }
+ else if (key < 0x10000) {
+ fm = ec_as2(kind, key, vf);
+ to = ec_as2(kind, key, vt);
+ }
+ else {
+ fm = ec_as4(kind, key, vf);
+ to = ec_as4(kind, key, vt);
+ }
+
+ struct f_tree *t = f_new_tree();
+ t->right = t;
+ t->from.type = t->to.type = T_EC;
+ t->from.val.ec = fm;
+ t->to.val.ec = to;
+ return t;
+}
+
+static inline struct f_inst *
+f_generate_empty(struct f_inst *dyn)
+{
+ struct f_inst *e = f_new_inst();
+ e->code = 'E';
+
+ switch (dyn->aux & EAF_TYPE_MASK) {
+ case EAF_TYPE_AS_PATH:
+ e->aux = T_PATH;
+ break;
+ case EAF_TYPE_INT_SET:
+ e->aux = T_CLIST;
+ break;
+ case EAF_TYPE_EC_SET:
+ e->aux = T_ECLIST;
+ break;
+ default:
+ cf_error("Can't empty that attribute");
+ }
+
+ 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)
+{
+ struct f_inst *rv;
+
+ if ((t1->code == 'c') && (t2->code == 'c')) {
+ if ((t1->aux != T_INT) || (t2->aux != T_INT))
+ cf_error( "Can't operate with value of non-integer type in pair constructor");
+
+ check_u16(t1->a2.i);
+ check_u16(t2->a2.i);
+
+ rv = f_new_inst();
+ rv->code = 'c';
+ rv->aux = T_PAIR;
+ rv->a2.i = pair(t1->a2.i, t2->a2.i);
+ }
+ else {
+ rv = f_new_inst();
+ rv->code = P('m', 'p');
+ rv->a1.p = t1;
+ rv->a2.p = t2;
+ }
+
+ return rv;
+}
+
+static inline struct f_inst *
+f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
+{
+ struct f_inst *rv;
+ int c1 = 0, c2 = 0, ipv4_used = 0;
+ u32 key = 0, val2 = 0;
+
+ if (tk->code == 'c') {
+ c1 = 1;
+
+ if (tk->aux == T_INT) {
+ ipv4_used = 0; key = tk->a2.i;
+ }
+ else if (tk->aux == T_QUAD) {
+ ipv4_used = 1; key = tk->a2.i;
+ }
+ else
+ cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
+ }
+
+#ifndef IPV6
+ /* IP->Quad implicit conversion */
+ else if (tk->code == 'C') {
+ c1 = 1;
+ struct f_val *val = tk->a1.p;
+ if (val->type == T_IP) {
+ ipv4_used = 1; key = ipa_to_u32(val->val.px.ip);
+ }
+ else
+ cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
+ }
+#endif
+
+ if (tv->code == 'c') {
+ if (tv->aux != T_INT)
+ cf_error("Can't operate with value of non-integer type in EC constructor");
+ c2 = 1;
+ val2 = tv->a2.i;
+ }
+
+ if (c1 && c2) {
+ u64 ec;
+
+ if (kind == EC_GENERIC) {
+ ec = ec_generic(key, val2);
+ }
+ else if (ipv4_used) {
+ check_u16(val2);
+ ec = ec_ip4(kind, key, val2);
+ }
+ else if (key < 0x10000) {
+ ec = ec_as2(kind, key, val2);
+ }
+ else {
+ check_u16(val2);
+ ec = ec_as4(kind, key, val2);
+ }
+
+ NEW_F_VAL;
+ rv = f_new_inst();
+ rv->code = 'C';
+ rv->a1.p = val;
+ val->type = T_EC;
+ val->val.ec = ec;
+ }
+ else {
+ rv = f_new_inst();
+ rv->code = P('m','c');
+ rv->aux = kind;
+ rv->a1.p = tk;
+ rv->a2.p = tv;
+ }
+
+ return rv;
+};
+
+
+
CF_DECLS
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ACCEPT, REJECT, ERROR, QUITBIRD,
- INT, BOOL, IP, PREFIX, PAIR, QUAD, SET, STRING, BGPMASK, BGPPATH, CLIST,
+ INT, BOOL, IP, PREFIX, PAIR, QUAD, EC,
+ SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST,
IF, THEN, ELSE, CASE,
- TRUE, FALSE,
+ TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, PREFERENCE,
LEN,
DEFINED,
@@ -93,11 +265,11 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%nonassoc THEN
%nonassoc ELSE
-%type <x> term block cmds cmds_int cmd function_body constant print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol dpair bgp_path_expr
+%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr
%type <f> filter filter_body where_filter
-%type <i> type break_command pair_expr
-%type <i32> pair_atom
-%type <e> pair_item set_item switch_item set_items switch_items switch_body
+%type <i> type break_command pair_expr ec_kind
+%type <i32> pair_atom ec_expr
+%type <e> pair_item ec_item set_item switch_item set_items switch_items switch_body
%type <trie> fprefix_set
%type <v> set_atom switch_atom fprefix fprefix_s fipa
%type <s> decls declsn one_decl function_params
@@ -128,15 +300,18 @@ type:
| PREFIX { $$ = T_PREFIX; }
| PAIR { $$ = T_PAIR; }
| QUAD { $$ = T_QUAD; }
+ | EC { $$ = T_EC; }
| STRING { $$ = T_STRING; }
| BGPMASK { $$ = T_PATH_MASK; }
| BGPPATH { $$ = T_PATH; }
| CLIST { $$ = T_CLIST; }
+ | ECLIST { $$ = T_ECLIST; }
| type SET {
switch ($1) {
case T_INT:
case T_PAIR:
case T_QUAD:
+ case T_EC:
case T_IP:
$$ = T_SET;
break;
@@ -324,14 +499,32 @@ pair_item:
}
;
+ec_expr:
+ term { $$ = f_eval_int($1); }
+
+ec_kind:
+ RT { $$ = EC_RT; }
+ | RO { $$ = EC_RO; }
+ | UNKNOWN NUM { $$ = $2; }
+ | GENERIC { $$ = EC_GENERIC; }
+ ;
+
+ec_item:
+ '(' ec_kind ',' ec_expr ',' ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
+ | '(' ec_kind ',' ec_expr ',' ec_expr DDOT ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
+ | '(' ec_kind ',' ec_expr ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
+ ;
+
set_item:
pair_item
+ | ec_item
| set_atom { $$ = f_new_item($1, $1); }
| set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
;
switch_item:
pair_item
+ | ec_item
| switch_atom { $$ = f_new_item($1, $1); }
| switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
;
@@ -411,20 +604,6 @@ bgp_path_tail2:
| { $$ = NULL; }
;
-dpair:
- '(' term ',' term ')' {
- if (($2->code == 'c') && ($4->code == 'c'))
- {
- if (($2->aux != T_INT) || ($4->aux != T_INT))
- cf_error( "Can't operate with value of non-integer type in pair constructor" );
- check_u16($2->a2.i); check_u16($4->a2.i);
- $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PAIR; $$->a2.i = pair($2->a2.i, $4->a2.i);
- }
- else
- { $$ = f_new_inst(); $$->code = P('m', 'p'); $$->a1.p = $2; $$->a2.p = $4; }
- }
- ;
-
constant:
NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
| TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
@@ -439,6 +618,11 @@ constant:
| bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
;
+constructor:
+ '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); };
+ | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); };
+ ;
+
/*
* Maybe there are no dynamic attributes defined by protocols.
@@ -490,6 +674,7 @@ symbol:
case SYM_VARIABLE | T_INT:
case SYM_VARIABLE | T_PAIR:
case SYM_VARIABLE | T_QUAD:
+ case SYM_VARIABLE | T_EC:
case SYM_VARIABLE | T_STRING:
case SYM_VARIABLE | T_IP:
case SYM_VARIABLE | T_PREFIX:
@@ -498,6 +683,7 @@ symbol:
case SYM_VARIABLE | T_PATH:
case SYM_VARIABLE | T_PATH_MASK:
case SYM_VARIABLE | T_CLIST:
+ case SYM_VARIABLE | T_ECLIST:
$$->code = 'V';
$$->a1.p = $1->def;
$$->a2.p = $1->name;
@@ -539,7 +725,7 @@ term:
| symbol { $$ = $1; }
| constant { $$ = $1; }
- | dpair { $$ = $1; }
+ | constructor { $$ = $1; }
| PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
@@ -563,6 +749,7 @@ term:
| '+' 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; }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; }
| ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
| DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
@@ -702,12 +889,11 @@ cmd:
}
- | rtadot dynamic_attr '.' EMPTY ';'
- { struct f_inst *i = f_new_inst(); i->code = 'E'; i->aux = T_CLIST; $$ = $2; $$->code = P('e','S'); $$->a1.p = i; }
+ | rtadot dynamic_attr '.' EMPTY ';' { $$ = 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 ); }
- | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $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 ); }
+ | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
;
CF_END