dect
/
libnl
Archived
13
0
Fork 0

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.
This commit is contained in:
Thomas Graf 2010-10-27 01:21:50 +02:00
parent b57a697ef1
commit 65e386c8ba
11 changed files with 292 additions and 75 deletions

View 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 *);

View 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
}

View 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",
};
/**

View 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;
}
/** @} */

View File

@ -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)

View File

@ -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;
}

View 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

49
man/nl-pktloc-lookup.8 Normal file
View File

@ -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.

1
src/.gitignore vendored
View File

@ -36,3 +36,4 @@ nl-tctree-list
nl-util-addr
nf-queue
nl-classid-lookup
nl-pktloc-lookup

View 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

View File

@ -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;
if (argc < 2)
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 (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;
}