Home | History | Annotate | Download | only in route
      1 /*
      2  * lib/route/pktloc.c     Packet Location Aliasing
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU General Public License as
      6  *	published by the Free Software Foundation version 2 of the License.
      7  *
      8  * Copyright (c) 2008-2010 Thomas Graf <tgraf (at) suug.ch>
      9  */
     10 
     11 /**
     12  * @ingroup tc
     13  * @defgroup pktloc Packet Location Aliasing
     14  * Packet Location Aliasing
     15  *
     16  * The packet location aliasing interface eases the use of offset definitions
     17  * inside packets by allowing them to be referenced by name. Known positions
     18  * of protocol fields are stored in a configuration file and associated with
     19  * a name for later reference. The configuration file is distributed with the
     20  * library and provides a well defined set of definitions for most common
     21  * protocol fields.
     22  *
     23  * @subsection pktloc_examples Examples
     24  * @par Example 1.1 Looking up a packet location
     25  * @code
     26  * struct rtnl_pktloc *loc;
     27  *
     28  * rtnl_pktloc_lookup("ip.src", &loc);
     29  * @endcode
     30  * @{
     31  */
     32 
     33 #include <netlink-local.h>
     34 #include <netlink-tc.h>
     35 #include <netlink/netlink.h>
     36 #include <netlink/utils.h>
     37 #include <netlink/route/pktloc.h>
     38 
     39 #include "pktloc_syntax.h"
     40 #include "pktloc_grammar.h"
     41 
     42 /** @cond */
     43 #define PKTLOC_NAME_HT_SIZ 256
     44 
     45 static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ];
     46 
     47 /* djb2 */
     48 unsigned int pktloc_hash(const char *str)
     49 {
     50 	unsigned long hash = 5381;
     51 	int c;
     52 
     53 	while ((c = *str++))
     54 		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
     55 
     56 	return hash % PKTLOC_NAME_HT_SIZ;
     57 }
     58 
     59 
     60 void rtnl_pktloc_add(struct rtnl_pktloc *loc)
     61 {
     62 	nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]);
     63 }
     64 
     65 extern int pktloc_parse(void *scanner);
     66 
     67 /** @endcond */
     68 
     69 static void rtnl_pktloc_free(struct rtnl_pktloc *loc)
     70 {
     71 	if (!loc)
     72 		return;
     73 
     74 	free(loc->name);
     75 	free(loc);
     76 }
     77 
     78 static int read_pktlocs(void)
     79 {
     80 	YY_BUFFER_STATE buf;
     81 	yyscan_t scanner = NULL;
     82 	static time_t last_read;
     83 	struct stat st = {0};
     84 	char *path;
     85 	int i, err;
     86 	FILE *fd;
     87 
     88 	asprintf(&path, "%s/pktloc", SYSCONFDIR);
     89 
     90 	/* if stat fails, just try to read the file */
     91 	if (stat(path, &st) == 0) {
     92 		/* Don't re-read file if file is unchanged */
     93 		if (last_read == st.st_mtime)
     94 			return 0;
     95 	}
     96 
     97 	if (!(fd = fopen(path, "r")))
     98 		return -NLE_PKTLOC_FILE;
     99 
    100 	for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) {
    101 		struct rtnl_pktloc *loc, *n;
    102 
    103 		nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list)
    104 			rtnl_pktloc_free(loc);
    105 
    106 		nl_init_list_head(&pktloc_name_ht[i]);
    107 	}
    108 
    109 	if ((err = pktloc_lex_init(&scanner)) < 0)
    110 		return -NLE_FAILURE;
    111 
    112 	buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner);
    113 	pktloc__switch_to_buffer(buf, scanner);
    114 
    115 	if ((err = pktloc_parse(scanner)) < 0)
    116 		return -NLE_FAILURE;
    117 
    118 	if (scanner)
    119 		pktloc_lex_destroy(scanner);
    120 
    121 	free(path);
    122 	last_read = st.st_mtime;
    123 
    124 	return 0;
    125 }
    126 
    127 /**
    128  * Lookup packet location alias
    129  * @arg name		Name of packet location.
    130  *
    131  * Tries to find a matching packet location alias for the supplied
    132  * packet location name.
    133  *
    134  * The file containing the packet location definitions is automatically
    135  * re-read if its modification time has changed since the last call.
    136  *
    137  * @return 0 on success or a negative error code.
    138  * @retval NLE_PKTLOC_FILE Unable to open packet location file.
    139  * @retval NLE_OBJ_NOTFOUND No matching packet location alias found.
    140  */
    141 int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
    142 {
    143 	struct rtnl_pktloc *loc;
    144 	int hash, err;
    145 
    146 	if ((err = read_pktlocs()) < 0)
    147 		return err;
    148 
    149 	hash = pktloc_hash(name);
    150 	nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) {
    151 		if (!strcasecmp(loc->name, name)) {
    152 			*result = loc;
    153 			return 0;
    154 		}
    155 	}
    156 
    157 	return -NLE_OBJ_NOTFOUND;
    158 }
    159 
    160 static int __init pktloc_init(void)
    161 {
    162 	int i;
    163 
    164 	for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
    165 		nl_init_list_head(&pktloc_name_ht[i]);
    166 
    167 	return 0;
    168 }
    169