diff options
Diffstat (limited to 'conf/flowspec.Y')
-rw-r--r-- | conf/flowspec.Y | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/conf/flowspec.Y b/conf/flowspec.Y new file mode 100644 index 00000000..4d259763 --- /dev/null +++ b/conf/flowspec.Y @@ -0,0 +1,209 @@ +/* + * BIRD -- Flow specification (RFC 5575) grammar + * + * (c) 2016 CZ.NIC z.s.p.o. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +CF_HDR + +#define PARSER 1 + +#include "nest/bird.h" +#include "lib/flowspec.h" + + +CF_DEFINES + +struct flow_builder *this_flow; + + +CF_DECLS + +%type <i32> flow_num_op flow_srcdst flow_logic_op flow_num_type_ flow_frag_val flow_neg +%type <net_ptr> net_flow4_ net_flow6_ net_flow_ + +CF_KEYWORDS(FLOW4, FLOW6, DST, SRC, PROTO, NEXT, HEADER, DPORT, SPORT, ICMP, + TYPE, CODE, TCP, FLAGS, LENGTH, DSCP, DONT_FRAGMENT, IS_FRAGMENT, + FIRST_FRAGMENT, LAST_FRAGMENT, FRAGMENT, LABEL, OFFSET) + + +CF_GRAMMAR + +/* Network Flow Specification */ + +flow_num_op: + TRUE { $$ = FLOW_OP_TRUE; } + | '=' { $$ = FLOW_OP_EQ; } + | NEQ { $$ = FLOW_OP_NEQ; } + | '<' { $$ = FLOW_OP_LT; } + | LEQ { $$ = FLOW_OP_LEQ; } + | '>' { $$ = FLOW_OP_GT; } + | GEQ { $$ = FLOW_OP_GEQ; } + | FALSE { $$ = FLOW_OP_FALSE; } + ; + +flow_logic_op: + OR { $$ = FLOW_OP_OR; } + | AND { $$ = FLOW_OP_AND; } + ; + +flow_num_type_: + PROTO { $$ = FLOW_TYPE_IP_PROTOCOL; } + | NEXT HEADER { $$ = FLOW_TYPE_NEXT_HEADER; } + | PORT { $$ = FLOW_TYPE_PORT; } + | DPORT { $$ = FLOW_TYPE_DST_PORT; } + | SPORT { $$ = FLOW_TYPE_SRC_PORT; } + | ICMP TYPE { $$ = FLOW_TYPE_ICMP_TYPE; } + | ICMP CODE { $$ = FLOW_TYPE_ICMP_CODE; } + | LENGTH { $$ = FLOW_TYPE_PACKET_LENGTH; } + | DSCP { $$ = FLOW_TYPE_DSCP; } + ; + +flow_num_type: flow_num_type_{ flow_builder_set_type(this_flow, $1); }; +flow_flag_type: TCP FLAGS { flow_builder_set_type(this_flow, FLOW_TYPE_TCP_FLAGS); }; +flow_frag_type: FRAGMENT { flow_builder_set_type(this_flow, FLOW_TYPE_FRAGMENT); }; +flow_label_type: LABEL { flow_builder_set_type(this_flow, FLOW_TYPE_LABEL); }; + +flow_srcdst: + DST { $$ = FLOW_TYPE_DST_PREFIX; } + | SRC { $$ = FLOW_TYPE_SRC_PREFIX; } + ; + +flow_num_opts: + flow_num_op expr { + flow_check_cf_value_length(this_flow, $2); + flow_builder_add_op_val(this_flow, $1, $2); + } + | flow_num_opts flow_logic_op flow_num_op expr { + flow_check_cf_value_length(this_flow, $4); + flow_builder_add_op_val(this_flow, $2 | $3, $4); + } + | flow_num_opt_ext + | flow_num_opts OR flow_num_opt_ext + ; + +flow_num_opt_ext_expr: + expr { + flow_check_cf_value_length(this_flow, $1); + flow_builder_add_op_val(this_flow, FLOW_OP_EQ, $1); + } + | expr DDOT expr { + flow_check_cf_value_length(this_flow, $1); + flow_check_cf_value_length(this_flow, $3); + flow_builder_add_op_val(this_flow, FLOW_OP_GEQ, $1); + flow_builder_add_op_val(this_flow, FLOW_OP_AND | FLOW_OP_LEQ, $3); + } + ; + +flow_num_opt_ext: + flow_num_opt_ext_expr + | flow_num_opt_ext ',' flow_num_opt_ext_expr + ; + +flow_bmk_opts: + flow_neg expr '/' expr { + flow_check_cf_bmk_values(this_flow, $1, $2, $4); + flow_builder_add_val_mask(this_flow, $1, $2, $4); + } + | flow_bmk_opts flow_logic_op flow_neg expr '/' expr { + flow_check_cf_bmk_values(this_flow, $3, $4, $6); + flow_builder_add_val_mask(this_flow, $2 | $3, $4, $6); + } + | flow_bmk_opts ',' flow_neg expr '/' expr { + flow_check_cf_bmk_values(this_flow, $3, $4, $6); + flow_builder_add_val_mask(this_flow, 0x40 | $3, $4, $6); /* AND */ + } + ; + +flow_neg: + /* empty */ { $$ = 0x00; } + | '!' { $$ = 0x02; } + ; + +flow_frag_val: + DONT_FRAGMENT { $$ = 1; } + | IS_FRAGMENT { $$ = 2; } + | FIRST_FRAGMENT { $$ = 4; } + | LAST_FRAGMENT { $$ = 8; } + ; + +flow_frag_opts: + flow_neg flow_frag_val { + flow_builder_add_val_mask(this_flow, 0, ($1 ? 0 : $2), $2); + } + | flow_frag_opts flow_logic_op flow_neg flow_frag_val { + flow_builder_add_val_mask(this_flow, $2, ($3 ? 0 : $4), $4); + } + | flow_frag_opts ',' flow_neg flow_frag_val { + flow_builder_add_val_mask(this_flow, 0x40, ($3 ? 0 : $4), $4); /* AND */ + } + ; + +flow4_item: + flow_srcdst net_ip { + flow_builder_set_type(this_flow, $1); + flow_builder4_add_pfx(this_flow, (net_addr_ip4 *) &($2)); + } + | flow_num_type flow_num_opts + | flow_flag_type flow_bmk_opts + | flow_frag_type flow_frag_opts + ; + +flow6_item: + flow_srcdst net_ip6 { + flow_builder_set_type(this_flow, $1); + flow_builder6_add_pfx(this_flow, (net_addr_ip6 *) &($2), 0); + } + | flow_srcdst net_ip6 OFFSET NUM { + if ($4 > $2.pxlen) + cf_error("Prefix offset is higher than prefix length"); + flow_builder_set_type(this_flow, $1); + flow_builder6_add_pfx(this_flow, (net_addr_ip6 *) &($2), $4); + } + | flow_num_type flow_num_opts + | flow_flag_type flow_bmk_opts + | flow_frag_type flow_frag_opts + | flow_label_type flow_bmk_opts + ; + +flow4_opts: + /* empty */ + | flow4_opts flow4_item ';' + ; + +flow6_opts: + /* empty */ + | flow6_opts flow6_item ';' + ; + +flow_builder_init: +{ + if (this_flow == NULL) + this_flow = flow_builder_init(&root_pool); + else + flow_builder_clear(this_flow); +}; + +flow_builder_set_ipv4: { this_flow->ipv6 = 0; }; +flow_builder_set_ipv6: { this_flow->ipv6 = 1; }; + +net_flow4_: FLOW4 '{' flow_builder_init flow_builder_set_ipv4 flow4_opts '}' +{ + $$ = (net_addr *) flow_builder4_finalize(this_flow, cfg_mem); + flow4_validate_cf((net_addr_flow4 *) $$); +}; + +net_flow6_: FLOW6 '{' flow_builder_init flow_builder_set_ipv6 flow6_opts '}' +{ + $$ = (net_addr *) flow_builder6_finalize(this_flow, cfg_mem); + flow6_validate_cf((net_addr_flow6 *) $$); +}; + +net_flow_: net_flow4_ | net_flow6_ ; + + +CF_CODE + +CF_END |