libnl 2.0

/tmp/buildd/libnl2-2.0/lib/route/pktloc.c

00001 /*
00002  * lib/route/pktloc.c     Packet Location Aliasing
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU General Public License as
00006  *      published by the Free Software Foundation version 2 of the License.
00007  *
00008  * Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch>
00009  */
00010 
00011 /**
00012  * @ingroup tc
00013  * @defgroup pktloc Packet Location Aliasing
00014  * Packet Location Aliasing
00015  *
00016  * The packet location aliasing interface eases the use of offset definitions
00017  * inside packets by allowing them to be referenced by name. Known positions
00018  * of protocol fields are stored in a configuration file and associated with
00019  * a name for later reference. The configuration file is distributed with the
00020  * library and provides a well defined set of definitions for most common
00021  * protocol fields.
00022  *
00023  * @subsection pktloc_examples Examples
00024  * @par Example 1.1 Looking up a packet location
00025  * @code
00026  * struct rtnl_pktloc *loc;
00027  *
00028  * rtnl_pktloc_lookup("ip.src", &loc);
00029  * @endcode
00030  * @{
00031  */
00032 
00033 #include <netlink-local.h>
00034 #include <netlink-tc.h>
00035 #include <netlink/netlink.h>
00036 #include <netlink/utils.h>
00037 #include <netlink/route/pktloc.h>
00038 
00039 #include "pktloc_syntax.h"
00040 #include "pktloc_grammar.h"
00041 
00042 /** @cond */
00043 #define PKTLOC_NAME_HT_SIZ 256
00044 
00045 static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ];
00046 
00047 /* djb2 */
00048 unsigned int pktloc_hash(const char *str)
00049 {
00050         unsigned long hash = 5381;
00051         int c;
00052 
00053         while ((c = *str++))
00054                 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
00055 
00056         return hash % PKTLOC_NAME_HT_SIZ;
00057 }
00058 
00059 
00060 void rtnl_pktloc_add(struct rtnl_pktloc *loc)
00061 {
00062         nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]);
00063 }
00064 
00065 extern int pktloc_parse(void *scanner);
00066 
00067 /** @endcond */
00068 
00069 static void rtnl_pktloc_free(struct rtnl_pktloc *loc)
00070 {
00071         if (!loc)
00072                 return;
00073 
00074         free(loc->name);
00075         free(loc);
00076 }
00077 
00078 static int read_pktlocs(void)
00079 {
00080         YY_BUFFER_STATE buf;
00081         yyscan_t scanner = NULL;
00082         static time_t last_read;
00083         struct stat st = {0};
00084         char *path;
00085         int i, err;
00086         FILE *fd;
00087 
00088         asprintf(&path, "%s/pktloc", SYSCONFDIR);
00089 
00090         /* if stat fails, just try to read the file */
00091         if (stat(path, &st) == 0) {
00092                 /* Don't re-read file if file is unchanged */
00093                 if (last_read == st.st_mtime)
00094                         return 0;
00095         }
00096 
00097         if (!(fd = fopen(path, "r")))
00098                 return -NLE_PKTLOC_FILE;
00099 
00100         for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) {
00101                 struct rtnl_pktloc *loc, *n;
00102 
00103                 nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list)
00104                         rtnl_pktloc_free(loc);
00105 
00106                 nl_init_list_head(&pktloc_name_ht[i]);
00107         }
00108 
00109         if ((err = pktloc_lex_init(&scanner)) < 0)
00110                 return -NLE_FAILURE;
00111 
00112         buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner);
00113         pktloc__switch_to_buffer(buf, scanner);
00114 
00115         if ((err = pktloc_parse(scanner)) < 0)
00116                 return -NLE_FAILURE;
00117 
00118         if (scanner)
00119                 pktloc_lex_destroy(scanner);
00120 
00121         free(path);
00122         last_read = st.st_mtime;
00123 
00124         return 0;
00125 }
00126 
00127 /**
00128  * Lookup packet location alias
00129  * @arg name            Name of packet location.
00130  *
00131  * Tries to find a matching packet location alias for the supplied
00132  * packet location name.
00133  *
00134  * The file containing the packet location definitions is automatically
00135  * re-read if its modification time has changed since the last call.
00136  *
00137  * @return 0 on success or a negative error code.
00138  * @retval NLE_PKTLOC_FILE Unable to open packet location file.
00139  * @retval NLE_OBJ_NOTFOUND No matching packet location alias found.
00140  */
00141 int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
00142 {
00143         struct rtnl_pktloc *loc;
00144         int hash, err;
00145 
00146         if ((err = read_pktlocs()) < 0)
00147                 return err;
00148 
00149         hash = pktloc_hash(name);
00150         nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) {
00151                 if (!strcasecmp(loc->name, name)) {
00152                         *result = loc;
00153                         return 0;
00154                 }
00155         }
00156 
00157         return -NLE_OBJ_NOTFOUND;
00158 }
00159 
00160 static int __init pktloc_init(void)
00161 {
00162         int i;
00163 
00164         for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
00165                 nl_init_list_head(&pktloc_name_ht[i]);
00166         
00167         return 0;
00168 }