]> granicus.if.org Git - libnl/commitdiff
Packet location updates
authorThomas Graf <tgraf@suug.ch>
Tue, 26 Oct 2010 23:21:50 +0000 (01:21 +0200)
committerThomas Graf <tgraf@suug.ch>
Tue, 26 Oct 2010 23:21:50 +0000 (01:21 +0200)
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.

include/netlink/errno.h
include/netlink/route/pktloc.h
lib/error.c
lib/route/pktloc.c
lib/route/pktloc_grammar.l
lib/route/pktloc_syntax.y
man/Makefile.am
man/nl-pktloc-lookup.8 [new file with mode: 0644]
src/.gitignore
src/Makefile.am
src/nl-pktloc-lookup.c

index c8a376e6c29896f335c9503747fa1b91de60d0de..dde12b7f81ad5e1963e4336941ceb2b414e5d370 100644 (file)
@@ -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 *);
index 28e1dc21fd6c27188eedd1985961da7a5df4ae9f..dbca8dc3adc4a2d7d5f70b72b8c026f776db8a18 100644 (file)
@@ -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
 }
index 9a9fac7f8ee0d7fc4ab8a621575400b762ee5edd..02cbbf12f8928a986b100258ce4a86f842e6ec35 100644 (file)
@@ -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",
 };
 
 /**
index f0d0155c96fcc0e8b15e02ff7f0e4b3485e6cba2..faf4bf5b21b316468d6f49a79c175d9bcc03ae4a 100644 (file)
@@ -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;
 }
+
+/** @} */
index f710430431ecf76d436988f0f58ac098577a3b5c..6b7a9339617ec1105350405b0da4a467356b0416 100644 (file)
@@ -11,6 +11,7 @@
 %option reentrant
 %option warn
 %option noyywrap
+%option noinput
 %option nounput
 %option bison-bridge
 %option bison-locations
 
 "+"                    { 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)
index 05d609a10936b37ae4c6513edf845246d326589e..bf00549ed5b807fada0f3b608cb4af4c1d783d26 100644 (file)
 
 %{
 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;
                }
index 5d628a43729c05469c730d110e8d3d9f19e73c7f..afbef3f53ba00b19d549519d326726cf0c42888b 100644 (file)
@@ -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 (file)
index 0000000..a583dcc
--- /dev/null
@@ -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.
index e7f47649311ab0095e72a4cb0a0242fafa6a0938..6385293470202c4305c50b7297ac1be86114ce2a 100644 (file)
@@ -36,3 +36,4 @@ nl-tctree-list
 nl-util-addr
 nf-queue
 nl-classid-lookup
+nl-pktloc-lookup
index 6ea3fee8d2eace62c6bb10289cd5fb0ef8ca2b5b..895c8ae11b915b3932779c2219adafb7e926ac3b 100644 (file)
@@ -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
index 09b04b246d4adcc126c4de4313fe4732fb95a68b..dc6154fc494b8e72504ada8417348476210ae5d6 100644 (file)
 
 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;
 }