]> git.ipfire.org Git - thirdparty/libnl.git/commitdiff
text ematch support
authorThomas Graf <tgraf@suug.ch>
Fri, 29 Oct 2010 19:10:02 +0000 (21:10 +0200)
committerThomas Graf <tgraf@suug.ch>
Fri, 29 Oct 2010 19:10:02 +0000 (21:10 +0200)
include/netlink/route/cls/ematch.h
include/netlink/route/cls/ematch/text.h [new file with mode: 0644]
lib/Makefile.am
lib/route/cls/ematch.c
lib/route/cls/ematch/text.c [new file with mode: 0644]
lib/route/cls/ematch_grammar.l
lib/route/cls/ematch_syntax.y

index 6cf59609354fb02caf7b895f649953ec88fe9398..52c4750eb8142cbee1bc0b82b9e1934ef3746c91 100644 (file)
@@ -84,6 +84,9 @@ extern void                   rtnl_ematch_tree_dump(struct rtnl_ematch_tree *,
 extern int                     rtnl_ematch_parse_expr(const char *, char **,
                                                       struct rtnl_ematch_tree **);
 
+extern char *                  rtnl_ematch_offset2txt(uint8_t, uint16_t,
+                                                      char *, size_t);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/netlink/route/cls/ematch/text.h b/include/netlink/route/cls/ematch/text.h
new file mode 100644 (file)
index 0000000..e599abf
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * netlink/route/cls/ematch/text.h     Text Search
+ *
+ *     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>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_TEXT_H_
+#define NETLINK_CLS_EMATCH_TEXT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_text.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void    rtnl_ematch_text_set_from(struct rtnl_ematch *,
+                                         uint8_t, uint16_t);
+extern uint16_t        rtnl_ematch_text_get_from_offset(struct rtnl_ematch *);
+extern uint8_t rtnl_ematch_text_get_from_layer(struct rtnl_ematch *);
+extern void    rtnl_ematch_text_set_to(struct rtnl_ematch *,
+                                       uint8_t, uint16_t);
+extern uint16_t        rtnl_ematch_text_get_to_offset(struct rtnl_ematch *);
+extern uint8_t rtnl_ematch_text_get_to_layer(struct rtnl_ematch *);
+extern void    rtnl_ematch_text_set_pattern(struct rtnl_ematch *,
+                                            char *, size_t);
+extern char *  rtnl_ematch_text_get_pattern(struct rtnl_ematch *);
+extern size_t  rtnl_ematch_text_get_len(struct rtnl_ematch *);
+extern void    rtnl_ematch_text_set_algo(struct rtnl_ematch *, const char *);
+extern char *  rtnl_ematch_text_get_algo(struct rtnl_ematch *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 98a28632315cc2548b56716117569a46a3bfd76d..7c869dcec752e6caafb464965b7da4b2a3a7cbac 100644 (file)
@@ -55,7 +55,7 @@ libnl_route_la_SOURCES = \
        route/cls/ematch_syntax.c route/cls/ematch_grammar.c \
        route/cls/ematch.c \
        route/cls/ematch/container.c route/cls/ematch/cmp.c \
-       route/cls/ematch/nbyte.c \
+       route/cls/ematch/nbyte.c route/cls/ematch/text.c \
        \
        route/link/api.c route/link/vlan.c \
        \
index b0943bfab081d863b792d4197723cd3f82c72430..76c34be4187c0ca0b38c691a6c1bf27c9c9b99dd 100644 (file)
@@ -667,4 +667,19 @@ errout:
        return err;
 }
 
+static const char *layer_txt[] = {
+       [TCF_LAYER_LINK]        = "eth",
+       [TCF_LAYER_NETWORK]     = "ip",
+       [TCF_LAYER_TRANSPORT]   = "tcp",
+};
+
+char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset, char *buf, size_t len)
+{
+       snprintf(buf, len, "%s+%u",
+                (layer <= TCF_LAYER_MAX) ? layer_txt[layer] : "?",
+                offset);
+
+       return buf;
+}
+
 /** @} */
diff --git a/lib/route/cls/ematch/text.c b/lib/route/cls/ematch/text.c
new file mode 100644 (file)
index 0000000..9d0241e
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * lib/route/cls/ematch/text.c         Text Search
+ *
+ *     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>
+ */
+
+/**
+ * @ingroup ematch
+ * @defgroup em_text Text Search
+ *
+ * @{
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/text.h>
+
+struct text_data
+{
+       struct tcf_em_text      cfg;
+       char *                  pattern;
+};
+
+void rtnl_ematch_text_set_from(struct rtnl_ematch *e, uint8_t layer,
+                              uint16_t offset)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       t->cfg.from_offset = offset;
+       t->cfg.from_layer = layer;
+}
+
+uint16_t rtnl_ematch_text_get_from_offset(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->cfg.from_offset;
+}
+
+uint8_t rtnl_ematch_text_get_from_layer(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->cfg.from_layer;
+}
+
+void rtnl_ematch_text_set_to(struct rtnl_ematch *e, uint8_t layer,
+                              uint16_t offset)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       t->cfg.to_offset = offset;
+       t->cfg.to_layer = layer;
+}
+
+uint16_t rtnl_ematch_text_get_to_offset(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->cfg.to_offset;
+}
+
+uint8_t rtnl_ematch_text_get_to_layer(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->cfg.to_layer;
+}
+
+void rtnl_ematch_text_set_pattern(struct rtnl_ematch *e,
+                                 char *pattern, size_t len)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+
+       if (t->pattern)
+               free(t->pattern);
+
+       t->pattern = pattern;
+       t->cfg.pattern_len = len;
+}
+
+char *rtnl_ematch_text_get_pattern(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->pattern;
+}
+
+size_t rtnl_ematch_text_get_len(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->cfg.pattern_len;
+}
+
+void rtnl_ematch_text_set_algo(struct rtnl_ematch *e, const char *algo)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+
+       strncpy(t->cfg.algo, algo, sizeof(t->cfg.algo));
+}
+
+char *rtnl_ematch_text_get_algo(struct rtnl_ematch *e)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+
+       return t->cfg.algo[0] ? t->cfg.algo : NULL;
+}
+
+static int text_parse(struct rtnl_ematch *e, void *data, size_t len)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       size_t hdrlen = sizeof(struct tcf_em_text);
+       size_t plen = len - hdrlen;
+
+       memcpy(&t->cfg, data, hdrlen);
+
+       if (t->cfg.pattern_len > plen)
+               return -NLE_INVAL;
+
+       if (t->cfg.pattern_len > 0) {
+               if (!(t->pattern = calloc(1, t->cfg.pattern_len)))
+                       return -NLE_NOMEM;
+
+               memcpy(t->pattern, data + hdrlen, t->cfg.pattern_len);
+       }
+
+       return 0;
+}
+
+static void text_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       char buf[64];
+
+       nl_dump(p, "text(%s \"%s\"",
+               t->cfg.algo[0] ? t->cfg.algo : "no-algo",
+               t->pattern ? : "no-pattern");
+
+       if (t->cfg.from_layer || t->cfg.from_offset) {
+               nl_dump(p, " from %s",
+                       rtnl_ematch_offset2txt(t->cfg.from_layer,
+                                              t->cfg.from_offset,
+                                              buf, sizeof(buf)));
+       }
+
+       if (t->cfg.to_layer || t->cfg.to_offset) {
+               nl_dump(p, " to %s",
+                       rtnl_ematch_offset2txt(t->cfg.to_layer,
+                                              t->cfg.to_offset,
+                                              buf, sizeof(buf)));
+       }
+
+       nl_dump(p, ")");
+}
+
+static int text_fill(struct rtnl_ematch *e, struct nl_msg *msg)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       int err;
+
+       if ((err = nlmsg_append(msg, &t->cfg, sizeof(t->cfg), 0)) < 0)
+               return err;
+
+       return nlmsg_append(msg, t->pattern, t->cfg.pattern_len, 0);
+}
+
+static void text_free(struct rtnl_ematch *e)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       free(t->pattern);
+}
+
+static struct rtnl_ematch_ops text_ops = {
+       .eo_kind        = TCF_EM_TEXT,
+       .eo_name        = "text",
+       .eo_minlen      = sizeof(struct tcf_em_text),
+       .eo_datalen     = sizeof(struct text_data),
+       .eo_parse       = text_parse,
+       .eo_dump        = text_dump,
+       .eo_fill        = text_fill,
+       .eo_free        = text_free,
+};
+
+static void __init text_init(void)
+{
+       rtnl_ematch_register(&text_ops);
+}
+
+/** @} */
index e345181db351666e40e21a2f9b1407d51c9a315a..998e86795728bf78ff473e5cb78727030f0914f0 100644 (file)
@@ -77,12 +77,15 @@ lt                  |
 
 [cC][mM][pP]           { yylval->i = TCF_EM_CMP; return EMATCH_CMP; }
 [pP][aA][tT][tT][eE][rR][nN] { yylval->i = TCF_EM_NBYTE; return EMATCH_NBYTE; }
+[tT][eE][xX][tT]       { yylval->i = TCF_EM_TEXT; return EMATCH_TEXT; }
 
 "("                    return KW_OPEN;
 ")"                    return KW_CLOSE;
 [mM][aA][sS][kK]       return KW_MASK;
 [aA][tT]               return KW_AT;
 "+"                    return KW_PLUS;
+[fF][rR][oO][mM]       return KW_FROM;
+[tT][oO]               return KW_TO;
 
 [uU]8                  { yylval->i = TCF_EM_ALIGN_U8; return ALIGN; }
 [uU]16                 { yylval->i = TCF_EM_ALIGN_U16; return ALIGN; }
index b6d04c99a63a6e8f61ce780ba94e7d19fe78f54e..26642a3946b530c0cb68542eb2b0d275f9e72594 100644 (file)
@@ -18,6 +18,7 @@
 #include <netlink/route/cls/ematch.h>
 #include <netlink/route/cls/ematch/cmp.h>
 #include <netlink/route/cls/ematch/nbyte.h>
+#include <netlink/route/cls/ematch/text.h>
 %}
 
 %error-verbose
@@ -56,9 +57,12 @@ static void yyerror(void *scanner, char **errp, struct nl_list_head *root, const
 %token <i> KW_AT "at"
 %token <i> EMATCH_CMP "cmp"
 %token <i> EMATCH_NBYTE "pattern"
+%token <i> EMATCH_TEXT "text"
 %token <i> KW_EQ "="
 %token <i> KW_GT ">"
 %token <i> KW_LT "<"
+%token <i> KW_FROM "from"
+%token <i> KW_TO "to"
 
 %token <s> STR
 
@@ -67,7 +71,7 @@ static void yyerror(void *scanner, char **errp, struct nl_list_head *root, const
 %type <i> mask align operand
 %type <e> expr match ematch
 %type <cmp> cmp_expr cmp_match
-%type <loc> pktloc
+%type <loc> pktloc text_from text_to
 %type <q> pattern
 
 %destructor { free($$); NL_DBG(2, "string destructor\n"); } <s>
@@ -144,8 +148,36 @@ ematch:
                                BUG();
 
                        rtnl_ematch_nbyte_set_offset(e, $3->layer, $3->offset);
+                       rtnl_pktloc_put($3);
                        rtnl_ematch_nbyte_set_pattern(e, (uint8_t *) $5.data, $5.index);
 
+                       $$ = e;
+               }
+       | EMATCH_TEXT "(" STR QUOTED text_from text_to ")"
+               {
+                       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_TEXT) < 0)
+                               BUG();
+
+                       rtnl_ematch_text_set_algo(e, $3);
+                       rtnl_ematch_text_set_pattern(e, $4.data, $4.index);
+
+                       if ($5) {
+                               rtnl_ematch_text_set_from(e, $5->layer, $5->offset);
+                               rtnl_pktloc_put($5);
+                       }
+
+                       if ($6) {
+                               rtnl_ematch_text_set_to(e, $6->layer, $6->offset);
+                               rtnl_pktloc_put($6);
+                       }
+
                        $$ = e;
                }
        /* CONTAINER */
@@ -198,9 +230,25 @@ cmp_expr:
                        $$.layer = $1->layer;
                        $$.opnd = $2;
                        $$.val = $3;
+
+                       rtnl_pktloc_put($1);
                }
        ;
 
+text_from:
+       /* empty */
+               { $$ = NULL; }
+       | "from" pktloc
+               { $$ = $2; }
+       ;
+
+text_to:
+       /* empty */
+               { $$ = NULL; }
+       | "to" pktloc
+               { $$ = $2; }
+       ;
+
 /*
  * pattern
  */
@@ -248,10 +296,16 @@ pktloc:
 
                        $$ = loc;
                }
-       | align "at" LAYER "+" NUMBER mask
+       /* [u8|u16|u32|NUM at] LAYER + OFFSET [mask MASK] */
+       | align LAYER "+" NUMBER mask
                {
                        struct rtnl_pktloc *loc;
 
+                       if ($5 && (!$1 || $1 > TCF_EM_ALIGN_U32)) {
+                               asprintf(errp, "mask only allowed for alignments u8|u16|u32");
+                               YYABORT;
+                       }
+
                        if (!(loc = rtnl_pktloc_alloc())) {
                                asprintf(errp, "Unable to allocate packet location object");
                                YYABORT;
@@ -259,18 +313,20 @@ pktloc:
 
                        loc->name = strdup("<USER-DEFINED>");
                        loc->align = $1;
-                       loc->layer = $3;
-                       loc->offset = $5;
-                       loc->mask = $6;
+                       loc->layer = $2;
+                       loc->offset = $4;
+                       loc->mask = $5;
 
                        $$ = loc;
                }
        ;
 
 align:
-       ALIGN
+       /* empty */
+               { $$ = 0; }
+       | ALIGN "at"
                { $$ = $1; }
-       | NUMBER
+       | NUMBER "at"
                { $$ = $1; }
        ;