summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2010-10-27 01:21:50 +0200
committerThomas Graf <tgraf@suug.ch>2010-10-27 01:21:50 +0200
commit65e386c8ba490d405f539322a12e1f1c7ea2eb5c (patch)
tree155a0dafacd32619123042f926a8d1638b28ed8b
parentb57a697ef1053a70264e9bedea3d2b98b8b24019 (diff)
downloadlibnl-65e386c8ba490d405f539322a12e1f1c7ea2eb5c.tar.gz
Packet location updates
This patch includes various bugfixes in the packet location parser. Namely it removes two memory leaks if parsing fails. The parser is correctly quit if an allocation error occurs and it is no longer possible to add duplicates. It removes the possibility to differ between net and host byteorder. This is better done in the actual classifiers as it makes more sense to specify this together with the value to compare against. The patch also extends the API to add new packet locations via rtnl_pktloc_add(). It introduces reference counting, therefore you now have to give back packet locations with rtnl_pktloc_put() after looking them up with rtnl_pktloc_lookup(). But you are allowed to keep using them if the packet location file has been reread. The packet location file now also understands "eth", "ip", and "tcp" for "link", "net", and "transport". A --list option has been added to nl-pktloc-lookup to list all packet location definitions A --u32=VALUE option has been added to let nl-pktloc-lookup print the definition in iproute2's u32 selector style. A manual page has been written for nl-pktloc-lookup. Finally, nl-pktloc-lookup has been made installable.
-rw-r--r--include/netlink/errno.h3
-rw-r--r--include/netlink/route/pktloc.h13
-rw-r--r--lib/error.c1
-rw-r--r--lib/route/pktloc.c124
-rw-r--r--lib/route/pktloc_grammar.l13
-rw-r--r--lib/route/pktloc_syntax.y45
-rw-r--r--man/Makefile.am1
-rw-r--r--man/nl-pktloc-lookup.849
-rw-r--r--src/.gitignore1
-rw-r--r--src/Makefile.am6
-rw-r--r--src/nl-pktloc-lookup.c111
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;
}