summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;
}