diff options
-rw-r--r-- | include/netlink/route/cls/ematch.h | 3 | ||||
-rw-r--r-- | include/netlink/route/cls/ematch/text.h | 42 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/route/cls/ematch.c | 15 | ||||
-rw-r--r-- | lib/route/cls/ematch/text.c | 183 | ||||
-rw-r--r-- | lib/route/cls/ematch_grammar.l | 3 | ||||
-rw-r--r-- | lib/route/cls/ematch_syntax.y | 70 |
7 files changed, 310 insertions, 8 deletions
diff --git a/include/netlink/route/cls/ematch.h b/include/netlink/route/cls/ematch.h index 6cf5960..52c4750 100644 --- a/include/netlink/route/cls/ematch.h +++ b/include/netlink/route/cls/ematch.h @@ -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 index 0000000..e599abf --- /dev/null +++ b/include/netlink/route/cls/ematch/text.h @@ -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 diff --git a/lib/Makefile.am b/lib/Makefile.am index 98a2863..7c869dc 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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 \ \ diff --git a/lib/route/cls/ematch.c b/lib/route/cls/ematch.c index b0943bf..76c34be 100644 --- a/lib/route/cls/ematch.c +++ b/lib/route/cls/ematch.c @@ -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 index 0000000..9d0241e --- /dev/null +++ b/lib/route/cls/ematch/text.c @@ -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); +} + +/** @} */ diff --git a/lib/route/cls/ematch_grammar.l b/lib/route/cls/ematch_grammar.l index e345181..998e867 100644 --- a/lib/route/cls/ematch_grammar.l +++ b/lib/route/cls/ematch_grammar.l @@ -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; } diff --git a/lib/route/cls/ematch_syntax.y b/lib/route/cls/ematch_syntax.y index b6d04c9..26642a3 100644 --- a/lib/route/cls/ematch_syntax.y +++ b/lib/route/cls/ematch_syntax.y @@ -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,10 +148,38 @@ 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 */ | "(" expr ")" { @@ -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; } ; |