summaryrefslogtreecommitdiff
path: root/conf
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2016-12-07 15:36:15 +0100
committerOndrej Zajicek (work) <santiago@crfreenet.org>2016-12-07 15:54:19 +0100
commit77234bbbde6bc328871af695e4450e6773adbafa (patch)
tree0ed60508b521eba6af6c4b852df09fdf8c659154 /conf
parentb94e5e58dbd33f4d2b9d721c51a9c8c4d8f77bea (diff)
Basic flow specification support (RFC 5575)
Add flow4/flow6 network and rt-table type and operations, config grammar and static protocol support. Squashed flowspec branch from Pavel Tvrdik.
Diffstat (limited to 'conf')
-rw-r--r--conf/Makefile2
-rw-r--r--conf/confbase.Y3
-rw-r--r--conf/flowspec.Y219
3 files changed, 221 insertions, 3 deletions
diff --git a/conf/Makefile b/conf/Makefile
index cc2b13c6..fb3dd052 100644
--- a/conf/Makefile
+++ b/conf/Makefile
@@ -10,7 +10,7 @@ BISON_DEBUG=-t
#FLEX_DEBUG=-d
endif
-$(conf-y-targets): $(s)confbase.Y
+$(conf-y-targets): $(s)confbase.Y $(s)flowspec.Y
$(M4) -P $| $^ >$@
$(o)cf-parse.y: | $(s)gen_parser.m4
diff --git a/conf/confbase.Y b/conf/confbase.Y
index 094c81b5..aec4aeb4 100644
--- a/conf/confbase.Y
+++ b/conf/confbase.Y
@@ -138,8 +138,6 @@ expr_us:
| expr US { $$ = (u32) $1 * 1; }
;
-/* expr_u16: expr { check_u16($1); $$ = $1; }; */
-
/* Switches */
bool:
@@ -220,6 +218,7 @@ net_roa_: net_roa4_ | net_roa6_ ;
net_:
net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
| net_roa_
+ | net_flow_
;
diff --git a/conf/flowspec.Y b/conf/flowspec.Y
new file mode 100644
index 00000000..a47d453b
--- /dev/null
+++ b/conf/flowspec.Y
@@ -0,0 +1,219 @@
+/*
+ * 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 "conf/conf.h"
+#include "lib/resource.h"
+#include "lib/socket.h"
+#include "sysdep/unix/timer.h"
+#include "lib/string.h"
+#include "nest/protocol.h"
+#include "nest/iface.h"
+#include "nest/route.h"
+#include "nest/cli.h"
+#include "filter/filter.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 { $$ = 0b000; }
+ | '=' { $$ = 0b001; }
+ | NEQ { $$ = 0b110; }
+ | '<' { $$ = 0b100; }
+ | LEQ { $$ = 0b101; }
+ | '>' { $$ = 0b010; }
+ | GEQ { $$ = 0b011; }
+ | FALSE { $$ = 0b111; }
+ ;
+
+flow_logic_op:
+ OR { $$ = 0x00; }
+ | AND { $$ = 0x40; }
+ ;
+
+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, 0b001, $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, 0b011, $1); /* >= */
+ flow_builder_add_op_val(this_flow, 0x40 | 0b101, $3); /* AND <= */
+ }
+ ;
+
+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