diff options
-rw-r--r-- | include/netlink/errno.h | 3 | ||||
-rw-r--r-- | include/netlink/route/pktloc.h | 13 | ||||
-rw-r--r-- | lib/error.c | 1 | ||||
-rw-r--r-- | lib/route/pktloc.c | 124 | ||||
-rw-r--r-- | lib/route/pktloc_grammar.l | 13 | ||||
-rw-r--r-- | lib/route/pktloc_syntax.y | 45 | ||||
-rw-r--r-- | man/Makefile.am | 1 | ||||
-rw-r--r-- | man/nl-pktloc-lookup.8 | 49 | ||||
-rw-r--r-- | src/.gitignore | 1 | ||||
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/nl-pktloc-lookup.c | 111 |
11 files changed, 292 insertions, 75 deletions
diff --git a/include/netlink/errno.h b/include/netlink/errno.h index c8a376e..dde12b7 100644 --- a/include/netlink/errno.h +++ b/include/netlink/errno.h @@ -46,8 +46,9 @@ extern "C" { #define NLE_NOACCESS 27 #define NLE_PERM 28 #define NLE_PKTLOC_FILE 29 +#define NLE_PARSE_ERR 30 -#define NLE_MAX NLE_PKTLOC_FILE +#define NLE_MAX NLE_PARSE_ERR extern const char * nl_geterror(int); extern void nl_perror(int, const char *); diff --git a/include/netlink/route/pktloc.h b/include/netlink/route/pktloc.h index 28e1dc2..dbca8dc 100644 --- a/include/netlink/route/pktloc.h +++ b/include/netlink/route/pktloc.h @@ -25,17 +25,20 @@ extern "C" { struct rtnl_pktloc { char * name; - uint8_t align:4; - uint8_t layer:4; - uint8_t flags; + uint8_t align; + uint8_t layer; uint16_t offset; uint32_t mask; + uint32_t refcnt; struct nl_list_head list; }; -extern int rtnl_pktloc_lookup(const char *, struct rtnl_pktloc **); - +extern int rtnl_pktloc_lookup(const char *, struct rtnl_pktloc **); +extern void rtnl_pktloc_put(struct rtnl_pktloc *); +extern int rtnl_pktloc_add(struct rtnl_pktloc *); +extern void rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *), + void *); #ifdef __cplusplus } diff --git a/lib/error.c b/lib/error.c index 9a9fac7..02cbbf1 100644 --- a/lib/error.c +++ b/lib/error.c @@ -43,6 +43,7 @@ static const char *errmsg[NLE_MAX+1] = { [NLE_NOACCESS] = "No Access", [NLE_PERM] = "Operation not permitted", [NLE_PKTLOC_FILE] = "Unable to open packet location file", +[NLE_PARSE_ERR] = "Unable to parse object", }; /** diff --git a/lib/route/pktloc.c b/lib/route/pktloc.c index f0d0155..faf4bf5 100644 --- a/lib/route/pktloc.c +++ b/lib/route/pktloc.c @@ -39,7 +39,7 @@ #include "pktloc_syntax.h" #include "pktloc_grammar.h" -/** @cond */ +/** @cond SKIP */ #define PKTLOC_NAME_HT_SIZ 256 static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ]; @@ -56,16 +56,25 @@ unsigned int pktloc_hash(const char *str) return hash % PKTLOC_NAME_HT_SIZ; } - -void rtnl_pktloc_add(struct rtnl_pktloc *loc) +static int __pktloc_lookup(const char *name, struct rtnl_pktloc **result) { - nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]); + struct rtnl_pktloc *loc; + int hash; + + hash = pktloc_hash(name); + nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) { + if (!strcasecmp(loc->name, name)) { + loc->refcnt++; + *result = loc; + return 0; + } + } + + return -NLE_OBJ_NOTFOUND; } extern int pktloc_parse(void *scanner); -/** @endcond */ - static void rtnl_pktloc_free(struct rtnl_pktloc *loc) { if (!loc) @@ -77,7 +86,7 @@ static void rtnl_pktloc_free(struct rtnl_pktloc *loc) static int read_pktlocs(void) { - YY_BUFFER_STATE buf; + YY_BUFFER_STATE buf = NULL; yyscan_t scanner = NULL; static time_t last_read; struct stat st = {0}; @@ -94,36 +103,51 @@ static int read_pktlocs(void) return 0; } - if (!(fd = fopen(path, "r"))) - return -NLE_PKTLOC_FILE; + NL_DBG(2, "Reading packet location file \"%s\"\n", path); + + if (!(fd = fopen(path, "r"))) { + err = -NLE_PKTLOC_FILE; + goto errout; + } for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) { struct rtnl_pktloc *loc, *n; nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list) - rtnl_pktloc_free(loc); + rtnl_pktloc_put(loc); nl_init_list_head(&pktloc_name_ht[i]); } - if ((err = pktloc_lex_init(&scanner)) < 0) - return -NLE_FAILURE; + if ((err = pktloc_lex_init(&scanner)) < 0) { + err = -NLE_FAILURE; + goto errout_close; + } buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner); pktloc__switch_to_buffer(buf, scanner); - if ((err = pktloc_parse(scanner)) < 0) - return -NLE_FAILURE; + if ((err = pktloc_parse(scanner)) != 0) { + pktloc__delete_buffer(buf, scanner); + err = -NLE_PARSE_ERR; + goto errout_scanner; + } + + last_read = st.st_mtime; +errout_scanner: if (scanner) pktloc_lex_destroy(scanner); - +errout_close: + fclose(fd); +errout: free(path); - last_read = st.st_mtime; return 0; } +/** @endcond */ + /** * Lookup packet location alias * @arg name Name of packet location. @@ -134,27 +158,75 @@ static int read_pktlocs(void) * The file containing the packet location definitions is automatically * re-read if its modification time has changed since the last call. * + * The returned packet location has to be returned after use by calling + * rtnl_pktloc_put() in order to allow freeing its memory after the last + * user has abandoned it. + * * @return 0 on success or a negative error code. * @retval NLE_PKTLOC_FILE Unable to open packet location file. * @retval NLE_OBJ_NOTFOUND No matching packet location alias found. */ int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result) { - struct rtnl_pktloc *loc; - int hash, err; + int err; if ((err = read_pktlocs()) < 0) return err; + + return __pktloc_lookup(name, result); +} - hash = pktloc_hash(name); - nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) { - if (!strcasecmp(loc->name, name)) { - *result = loc; - return 0; - } +/** + * Return reference of a packet location + * @arg loc packet location object. + */ +void rtnl_pktloc_put(struct rtnl_pktloc *loc) +{ + if (!loc) + return; + + loc->refcnt--; + if (loc->refcnt <= 0) + rtnl_pktloc_free(loc); +} + +/** + * Add a packet location to the hash table + * @arg loc packet location object + * + * @return 0 on success or a negative error code. + */ +int rtnl_pktloc_add(struct rtnl_pktloc *loc) +{ + struct rtnl_pktloc *l; + + if (__pktloc_lookup(loc->name, &l) == 0) { + rtnl_pktloc_put(l); + return -NLE_EXIST; } - return -NLE_OBJ_NOTFOUND; + loc->refcnt++; + + NL_DBG(2, "New packet location entry \"%s\" align=%u layer=%u " + "offset=%u mask=%#x refnt=%u\n", loc->name, loc->align, + loc->layer, loc->offset, loc->mask, loc->refcnt); + + nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]); + + return 0; +} + +void rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *), void *arg) +{ + struct rtnl_pktloc *loc; + int i; + + /* ignore errors */ + read_pktlocs(); + + for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) + nl_list_for_each_entry(loc, &pktloc_name_ht[i], list) + cb(loc, arg); } static int __init pktloc_init(void) @@ -166,3 +238,5 @@ static int __init pktloc_init(void) return 0; } + +/** @} */ diff --git a/lib/route/pktloc_grammar.l b/lib/route/pktloc_grammar.l index f710430..6b7a933 100644 --- a/lib/route/pktloc_grammar.l +++ b/lib/route/pktloc_grammar.l @@ -11,6 +11,7 @@ %option reentrant %option warn %option noyywrap +%option noinput %option nounput %option bison-bridge %option bison-locations @@ -30,10 +31,18 @@ "+" { return yylval->i = yytext[0]; } -[lL][iI][nN][kK] { yylval->i = TCF_LAYER_LINK; return LAYER; } -[nN][eE][tT] { yylval->i = TCF_LAYER_NETWORK; return LAYER; } +[uU]8 { yylval->i = TCF_EM_ALIGN_U8; return ALIGN; } +[uU]16 { yylval->i = TCF_EM_ALIGN_U16; return ALIGN; } +[uU]32 { yylval->i = TCF_EM_ALIGN_U32; return ALIGN; } + +[lL][iI][nN][kK] | +[eE][tT][hH] { yylval->i = TCF_LAYER_LINK; return LAYER; } +[nN][eE][tT] | +[iI][pP] { yylval->i = TCF_LAYER_NETWORK; return LAYER; } +[tT][rR][aA][nN][sS][pP][oO][rR][tT] | [tT][cC][pP] { yylval->i = TCF_LAYER_TRANSPORT; return LAYER; } + [^ \t\r\n+]+ { yylval->s = strdup(yytext); if (yylval->s == NULL) diff --git a/lib/route/pktloc_syntax.y b/lib/route/pktloc_syntax.y index 05d609a..bf00549 100644 --- a/lib/route/pktloc_syntax.y +++ b/lib/route/pktloc_syntax.y @@ -22,15 +22,14 @@ %{ extern int pktloc_lex(YYSTYPE *, YYLTYPE *, void *); -extern void rtnl_pktloc_add(struct rtnl_pktloc *); static void yyerror(YYLTYPE *locp, void *scanner, const char *msg) { - /* FIXME */ + NL_DBG(1, "Error while parsing packet location file: %s\n", msg); } %} -%token <i> ERROR NUMBER LAYER +%token <i> ERROR NUMBER LAYER ALIGN %token <s> NAME %type <i> mask layer @@ -43,51 +42,31 @@ static void yyerror(YYLTYPE *locp, void *scanner, const char *msg) %% input: - def - { } - ; - -def: /* empty */ - { } - | location def - { } + | location input ; location: - NAME NAME layer NUMBER mask + NAME ALIGN layer NUMBER mask { struct rtnl_pktloc *loc; if (!(loc = calloc(1, sizeof(*loc)))) { - /* FIXME */ + NL_DBG(1, "Allocating a packet location " + "object failed.\n"); + YYABORT; } - if (!strcasecmp($2, "u8")) - loc->align = TCF_EM_ALIGN_U8; - else if (!strcasecmp($2, "h8")) { - loc->align = TCF_EM_ALIGN_U8; - loc->flags = TCF_EM_CMP_TRANS; - } else if (!strcasecmp($2, "u16")) - loc->align = TCF_EM_ALIGN_U16; - else if (!strcasecmp($2, "h16")) { - loc->align = TCF_EM_ALIGN_U16; - loc->flags = TCF_EM_CMP_TRANS; - } else if (!strcasecmp($2, "u32")) - loc->align = TCF_EM_ALIGN_U32; - else if (!strcasecmp($2, "h32")) { - loc->align = TCF_EM_ALIGN_U32; - loc->flags = TCF_EM_CMP_TRANS; - } - - free($2); - loc->name = $1; + loc->align = $2; loc->layer = $3; loc->offset = $4; loc->mask = $5; - rtnl_pktloc_add(loc); + if (rtnl_pktloc_add(loc) < 0) { + NL_DBG(1, "Duplicate packet location entry " + "\"%s\"\n", $1); + } $$ = loc; } diff --git a/man/Makefile.am b/man/Makefile.am index 5d628a4..afbef3f 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -2,4 +2,5 @@ dist_man8_MANS = \ nl-classid-lookup.8 \ + nl-pktloc-lookup.8 \ nl-qdisc-add.8 nl-qdisc-delete.8 nl-qdisc-list.8 diff --git a/man/nl-pktloc-lookup.8 b/man/nl-pktloc-lookup.8 new file mode 100644 index 0000000..a583dcc --- /dev/null +++ b/man/nl-pktloc-lookup.8 @@ -0,0 +1,49 @@ +.TH nl\-pktloc-lookup 8 "27 October 2010" "libnl" +.LO 1 +.SH NAME +nl\-pktloc\-lookup - Lookup packet location definitions +.SH SYNOPSIS +.B nl\-pktloc\-lookup +.I name +.br +.B nl\-pktloc\-lookup \-\-list + +.SH DESCRIPTION +.PP +nl\-pktloc\-lookup searches the packet location database for a matching +entry. It is used to resolve packet location aliases to their definition, +i.e. alignment, layer, offset, and mask. + +.SH OPTIONS +.TP +.BR \-\^h " or " \-\-help +Print help text to console and exit. +.TP +.BR \-\^v " or " \-\-version +Print versioning information to console and exit. +.TP +.BR \-\^l " or " \-\-list +List all packet location definitions. +.TP +.BR \-\-u32=VALUE +Prints the packet location definition in a special format that is +understood by iproute2's u32 selector parser. It will output a +u32 selector which will compare the provided value with the value +specified by the packet location. + +Please note that due to the limitation of u32, it is not possible +to use packet locations based on the link layer. nl-pktloc-lookup +will print an error message in this case. + +Example: + selector=$(nl-pktloc-lookup --u32 22 tcp.sport) + tc filter add [...] u32 match $(selector) flowid 1:2 + +.SH FILES +.PP +/etc/libnl/pktloc + +.SH AUTHOR +.PP +Thomas Graf is the original author and current maintainer of libnl and +libnl tools. Many people have contributed to it since. diff --git a/src/.gitignore b/src/.gitignore index e7f4764..6385293 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -36,3 +36,4 @@ nl-tctree-list nl-util-addr nf-queue nl-classid-lookup +nl-pktloc-lookup diff --git a/src/Makefile.am b/src/Makefile.am index 6ea3fee..895c8ae 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,7 +9,8 @@ sbin_PROGRAMS = \ nl-qdisc-add nl-qdisc-list nl-qdisc-delete \ nl-class-add nl-class-list nl-class-delete \ nl-cls-add nl-cls-list nl-cls-delete \ - nl-classid-lookup + nl-classid-lookup \ + nl-pktloc-lookup noinst_PROGRAMS = \ genl-ctrl-list \ @@ -25,8 +26,7 @@ noinst_PROGRAMS = \ nl-route-add nl-route-delete nl-route-get nl-route-list \ nl-fib-lookup \ nl-list-caches nl-list-sockets \ - nl-util-addr \ - nl-pktloc-lookup + nl-util-addr genl_ctrl_list_SOURCES = genl-ctrl-list.c genl_ctrl_list_LDADD = -lnl-genl -lnl-route diff --git a/src/nl-pktloc-lookup.c b/src/nl-pktloc-lookup.c index 09b04b2..dc6154f 100644 --- a/src/nl-pktloc-lookup.c +++ b/src/nl-pktloc-lookup.c @@ -14,24 +14,123 @@ static void print_usage(void) { - printf("Usage: nl-pktloc-lookup <name>\n"); +printf( +"Usage: nl-pktloc-lookup [OPTIONS] <name>\n" +"\n" +"OPTIONS\n" +" -h, --help Show this help text.\n" +" -v, --version Show versioning information.\n" +" -l, --list List all packet location definitions.\n" +" --u32=VALUE Print in iproute2's u32 selector style\n" +"\n" +"\n" +"EXAMPLE\n" +" $ nl-pktloc-lookup ip.dst\n" +" $ nl-pktloc-lookup --list\n" +"\n" +); exit(0); } +static const char *align_txt[] = { + [TCF_EM_ALIGN_U8] = "u8", + [TCF_EM_ALIGN_U16] = "u16", + [TCF_EM_ALIGN_U32] = "u32" +}; + +static uint32_t align_mask[] = { + [TCF_EM_ALIGN_U8] = 0xff, + [TCF_EM_ALIGN_U16] = 0xffff, + [TCF_EM_ALIGN_U32] = 0xffffffff, +}; + +static const char *layer_txt[] = { + [TCF_LAYER_LINK] = "eth", + [TCF_LAYER_NETWORK] = "ip", + [TCF_LAYER_TRANSPORT] = "tcp" +}; + +static void dump_u32_style(struct rtnl_pktloc *loc, uint32_t value) +{ + if (loc->layer == TCF_LAYER_LINK) + nl_cli_fatal(EINVAL, "u32 does not support link " + "layer locations."); + + printf("%s %x %x at %s%u\n", + align_txt[loc->align], + value, loc->mask ? loc->mask : align_mask[loc->align], + loc->layer == TCF_LAYER_TRANSPORT ? "nexthdr+" : "", + loc->offset); +} + +static void dump_loc(struct rtnl_pktloc *loc) +{ + printf("%s = %s at %s+%u %#x\n", + loc->name, align_txt[loc->align], + layer_txt[loc->layer], loc->offset, loc->mask); +} + +static void list_cb(struct rtnl_pktloc *loc, void *arg) +{ + printf("%-26s %-5s %3s+%-4u %#-10x %u\n", + loc->name, align_txt[loc->align], + layer_txt[loc->layer], loc->offset, + loc->mask, loc->refcnt); +} + +static void do_list(void) +{ + printf("name align offset mask refcnt\n"); + printf("---------------------------------------------------------\n"); + + rtnl_pktloc_foreach(&list_cb, NULL); +} + int main(int argc, char *argv[]) { struct rtnl_pktloc *loc; - int err; + int err, ustyle = 0; + uint32_t uvalue = 0; + + for (;;) { + int c, optidx = 0; + enum { + ARG_U32 = 257, + }; + static struct option long_opts[] = { + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { "list", 0, 0, 'l' }, + { "u32", 1, 0, ARG_U32 }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "hvl", long_opts, &optidx); + if (c == -1) + break; + + switch (c) { + case 'h': print_usage(); break; + case 'v': nl_cli_print_version(); break; + case 'l': do_list(); exit(0); + case ARG_U32: + ustyle = 1; + uvalue = nl_cli_parse_u32(optarg); + break; + } + } - if (argc < 2) + if (optind >= argc) print_usage(); - if ((err = rtnl_pktloc_lookup(argv[1], &loc)) < 0) + if ((err = rtnl_pktloc_lookup(argv[optind++], &loc)) < 0) nl_cli_fatal(err, "Unable to lookup packet location: %s", nl_geterror(err)); - printf("%s: %u %u+%u 0x%x %u\n", loc->name, loc->align, - loc->layer, loc->offset, loc->mask, loc->flags); + if (ustyle) + dump_u32_style(loc, uvalue); + else + dump_loc(loc); return 0; } |