summaryrefslogtreecommitdiffstats
path: root/lib/route/cls/ematch_syntax.y
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2010-10-28 22:20:42 (GMT)
committerThomas Graf <tgraf@suug.ch>2010-10-28 22:20:42 (GMT)
commitd7a561a1372f819efc8cede30dc550d8e3afcc28 (patch)
treeda9fefa62f5ffdca82fa374ebe0b207202719410 /lib/route/cls/ematch_syntax.y
parente1eacd6b16b014eb42bcf6683ebe2334c3a35c68 (diff)
downloadlibnl-d7a561a1372f819efc8cede30dc550d8e3afcc28.zip
libnl-d7a561a1372f819efc8cede30dc550d8e3afcc28.tar.gz
libnl-d7a561a1372f819efc8cede30dc550d8e3afcc28.tar.bz2
Tons of ematch work
- Fixes a bunch of bugs related to ematches - Adds support for the nbyte ematch - Adds a bison/flex parser for ematch expressions, expressions may look like this: ip.length > 256 && pattern(ip6.src = 3ffe::/16) documenation on syntax follows - adds ematch support to the basic classifier (--ematch EXPR)
Diffstat (limited to 'lib/route/cls/ematch_syntax.y')
-rw-r--r--lib/route/cls/ematch_syntax.y291
1 files changed, 291 insertions, 0 deletions
diff --git a/lib/route/cls/ematch_syntax.y b/lib/route/cls/ematch_syntax.y
new file mode 100644
index 0000000..b6d04c9
--- /dev/null
+++ b/lib/route/cls/ematch_syntax.y
@@ -0,0 +1,291 @@
+/*
+ * lib/route/cls/ematch_syntax.y ematch expression syntax
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+%{
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/pktloc.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/cmp.h>
+#include <netlink/route/cls/ematch/nbyte.h>
+%}
+
+%error-verbose
+%define api.pure
+%name-prefix "ematch_"
+
+%parse-param {void *scanner}
+%parse-param {char **errp}
+%parse-param {struct nl_list_head *root}
+%lex-param {void *scanner}
+
+%union {
+ struct tcf_em_cmp cmp;
+ struct ematch_quoted q;
+ struct rtnl_ematch * e;
+ struct rtnl_pktloc * loc;
+ uint32_t i;
+ char * s;
+}
+
+%{
+extern int ematch_lex(YYSTYPE *, void *);
+
+static void yyerror(void *scanner, char **errp, struct nl_list_head *root, const char *msg)
+{
+ if (msg)
+ asprintf(errp, "%s", msg);
+}
+%}
+
+%token <i> ERROR LOGIC NOT OPERAND NUMBER ALIGN LAYER
+%token <i> KW_OPEN "("
+%token <i> KW_CLOSE ")"
+%token <i> KW_PLUS "+"
+%token <i> KW_MASK "mask"
+%token <i> KW_AT "at"
+%token <i> EMATCH_CMP "cmp"
+%token <i> EMATCH_NBYTE "pattern"
+%token <i> KW_EQ "="
+%token <i> KW_GT ">"
+%token <i> KW_LT "<"
+
+%token <s> STR
+
+%token <q> QUOTED
+
+%type <i> mask align operand
+%type <e> expr match ematch
+%type <cmp> cmp_expr cmp_match
+%type <loc> pktloc
+%type <q> pattern
+
+%destructor { free($$); NL_DBG(2, "string destructor\n"); } <s>
+%destructor { rtnl_pktloc_put($$); NL_DBG(2, "pktloc destructor\n"); } <loc>
+%destructor { free($$.data); NL_DBG(2, "quoted destructor\n"); } <q>
+
+%start input
+
+%%
+
+input:
+ /* empty */
+ | expr
+ {
+ nl_list_add_tail(root, &$1->e_list);
+ }
+ ;
+
+expr:
+ match
+ {
+ $$ = $1;
+ }
+ | match LOGIC expr
+ {
+ rtnl_ematch_set_flags($1, $2);
+
+ /* make ematch new head */
+ nl_list_add_tail(&$1->e_list, &$3->e_list);
+
+ $$ = $1;
+ }
+ ;
+
+match:
+ NOT ematch
+ {
+ rtnl_ematch_set_flags($2, TCF_EM_INVERT);
+ $$ = $2;
+ }
+ | ematch
+ {
+ $$ = $1;
+ }
+ ;
+
+ematch:
+ /* CMP */
+ cmp_match
+ {
+ struct rtnl_ematch *e;
+
+ if (!(e = rtnl_ematch_alloc())) {
+ asprintf(errp, "Unable to allocate ematch object");
+ YYABORT;
+ }
+
+ if (rtnl_ematch_set_kind(e, TCF_EM_CMP) < 0)
+ BUG();
+
+ rtnl_ematch_cmp_set(e, &$1);
+ $$ = e;
+ }
+ | EMATCH_NBYTE "(" pktloc KW_EQ pattern ")"
+ {
+ struct rtnl_ematch *e;
+
+ if (!(e = rtnl_ematch_alloc())) {
+ asprintf(errp, "Unable to allocate ematch object");
+ YYABORT;
+ }
+
+ if (rtnl_ematch_set_kind(e, TCF_EM_NBYTE) < 0)
+ BUG();
+
+ rtnl_ematch_nbyte_set_offset(e, $3->layer, $3->offset);
+ rtnl_ematch_nbyte_set_pattern(e, (uint8_t *) $5.data, $5.index);
+
+ $$ = e;
+ }
+ /* CONTAINER */
+ | "(" expr ")"
+ {
+ struct rtnl_ematch *e;
+
+ if (!(e = rtnl_ematch_alloc())) {
+ asprintf(errp, "Unable to allocate ematch object");
+ YYABORT;
+ }
+
+ if (rtnl_ematch_set_kind(e, TCF_EM_CONTAINER) < 0)
+ BUG();
+
+ /* Make e->childs the list head of a the ematch sequence */
+ nl_list_add_tail(&e->e_childs, &$2->e_list);
+
+ $$ = e;
+ }
+ ;
+
+/*
+ * CMP match
+ *
+ * match := cmp(expr) | expr
+ * expr := pktloc (=|>|<) NUMBER
+ * pktloc := alias | definition
+ *
+ */
+cmp_match:
+ EMATCH_CMP "(" cmp_expr ")"
+ { $$ = $3; }
+ | cmp_expr
+ { $$ = $1; }
+ ;
+
+cmp_expr:
+ pktloc operand NUMBER
+ {
+ if ($1->align == TCF_EM_ALIGN_U16 ||
+ $1->align == TCF_EM_ALIGN_U32)
+ $$.flags = TCF_EM_CMP_TRANS;
+
+ memset(&$$, 0, sizeof($$));
+
+ $$.mask = $1->mask;
+ $$.off = $1->offset;
+ $$.align = $1->align;
+ $$.layer = $1->layer;
+ $$.opnd = $2;
+ $$.val = $3;
+ }
+ ;
+
+/*
+ * pattern
+ */
+pattern:
+ QUOTED
+ {
+ $$ = $1;
+ }
+ | STR
+ {
+ struct nl_addr *addr;
+
+ if (nl_addr_parse($1, AF_UNSPEC, &addr) == 0) {
+ $$.len = nl_addr_get_len(addr);
+
+ $$.index = min_t(int, $$.len, nl_addr_get_prefixlen(addr)/8);
+
+ if (!($$.data = calloc(1, $$.len))) {
+ nl_addr_put(addr);
+ YYABORT;
+ }
+
+ memcpy($$.data, nl_addr_get_binary_addr(addr), $$.len);
+ nl_addr_put(addr);
+ } else {
+ asprintf(errp, "invalid pattern \"%s\"", $1);
+ YYABORT;
+ }
+ }
+ ;
+
+/*
+ * packet location
+ */
+
+pktloc:
+ STR
+ {
+ struct rtnl_pktloc *loc;
+
+ if (rtnl_pktloc_lookup($1, &loc) < 0) {
+ asprintf(errp, "Packet location \"%s\" not found", $1);
+ YYABORT;
+ }
+
+ $$ = loc;
+ }
+ | align "at" LAYER "+" NUMBER mask
+ {
+ struct rtnl_pktloc *loc;
+
+ if (!(loc = rtnl_pktloc_alloc())) {
+ asprintf(errp, "Unable to allocate packet location object");
+ YYABORT;
+ }
+
+ loc->name = strdup("<USER-DEFINED>");
+ loc->align = $1;
+ loc->layer = $3;
+ loc->offset = $5;
+ loc->mask = $6;
+
+ $$ = loc;
+ }
+ ;
+
+align:
+ ALIGN
+ { $$ = $1; }
+ | NUMBER
+ { $$ = $1; }
+ ;
+
+mask:
+ /* empty */
+ { $$ = 0; }
+ | "mask" NUMBER
+ { $$ = $2; }
+ ;
+
+operand:
+ KW_EQ
+ { $$ = TCF_EM_OPND_EQ; }
+ | KW_GT
+ { $$ = TCF_EM_OPND_GT; }
+ | KW_LT
+ { $$ = TCF_EM_OPND_LT; }
+ ;