diff options
Diffstat (limited to 'filter/config.Y')
-rw-r--r-- | filter/config.Y | 238 |
1 files changed, 212 insertions, 26 deletions
diff --git a/filter/config.Y b/filter/config.Y index 80e74286..3c5f18b7 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 |