libnl 2.0
|
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 }