libnl 3.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 SKIP */ 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 static int __pktloc_lookup(const char *name, struct rtnl_pktloc **result) 00060 { 00061 struct rtnl_pktloc *loc; 00062 int hash; 00063 00064 hash = pktloc_hash(name); 00065 nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) { 00066 if (!strcasecmp(loc->name, name)) { 00067 loc->refcnt++; 00068 *result = loc; 00069 return 0; 00070 } 00071 } 00072 00073 return -NLE_OBJ_NOTFOUND; 00074 } 00075 00076 extern int pktloc_parse(void *scanner); 00077 00078 static void rtnl_pktloc_free(struct rtnl_pktloc *loc) 00079 { 00080 if (!loc) 00081 return; 00082 00083 free(loc->name); 00084 free(loc); 00085 } 00086 00087 static int read_pktlocs(void) 00088 { 00089 YY_BUFFER_STATE buf = NULL; 00090 yyscan_t scanner = NULL; 00091 static time_t last_read; 00092 struct stat st = {0}; 00093 char *path; 00094 int i, err; 00095 FILE *fd; 00096 00097 asprintf(&path, "%s/pktloc", SYSCONFDIR); 00098 00099 /* if stat fails, just try to read the file */ 00100 if (stat(path, &st) == 0) { 00101 /* Don't re-read file if file is unchanged */ 00102 if (last_read == st.st_mtime) 00103 return 0; 00104 } 00105 00106 NL_DBG(2, "Reading packet location file \"%s\"\n", path); 00107 00108 if (!(fd = fopen(path, "r"))) { 00109 err = -NLE_PKTLOC_FILE; 00110 goto errout; 00111 } 00112 00113 for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) { 00114 struct rtnl_pktloc *loc, *n; 00115 00116 nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list) 00117 rtnl_pktloc_put(loc); 00118 00119 nl_init_list_head(&pktloc_name_ht[i]); 00120 } 00121 00122 if ((err = pktloc_lex_init(&scanner)) < 0) { 00123 err = -NLE_FAILURE; 00124 goto errout_close; 00125 } 00126 00127 buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner); 00128 pktloc__switch_to_buffer(buf, scanner); 00129 00130 if ((err = pktloc_parse(scanner)) != 0) { 00131 pktloc__delete_buffer(buf, scanner); 00132 err = -NLE_PARSE_ERR; 00133 goto errout_scanner; 00134 } 00135 00136 last_read = st.st_mtime; 00137 00138 errout_scanner: 00139 if (scanner) 00140 pktloc_lex_destroy(scanner); 00141 errout_close: 00142 fclose(fd); 00143 errout: 00144 free(path); 00145 00146 return 0; 00147 } 00148 00149 /** @endcond */ 00150 00151 /** 00152 * Lookup packet location alias 00153 * @arg name Name of packet location. 00154 * 00155 * Tries to find a matching packet location alias for the supplied 00156 * packet location name. 00157 * 00158 * The file containing the packet location definitions is automatically 00159 * re-read if its modification time has changed since the last call. 00160 * 00161 * The returned packet location has to be returned after use by calling 00162 * rtnl_pktloc_put() in order to allow freeing its memory after the last 00163 * user has abandoned it. 00164 * 00165 * @return 0 on success or a negative error code. 00166 * @retval NLE_PKTLOC_FILE Unable to open packet location file. 00167 * @retval NLE_OBJ_NOTFOUND No matching packet location alias found. 00168 */ 00169 int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result) 00170 { 00171 int err; 00172 00173 if ((err = read_pktlocs()) < 0) 00174 return err; 00175 00176 return __pktloc_lookup(name, result); 00177 } 00178 00179 /** 00180 * Allocate packet location object 00181 */ 00182 struct rtnl_pktloc *rtnl_pktloc_alloc(void) 00183 { 00184 struct rtnl_pktloc *loc; 00185 00186 if (!(loc = calloc(1, sizeof(*loc)))) 00187 return NULL; 00188 00189 loc->refcnt = 1; 00190 nl_init_list_head(&loc->list); 00191 00192 return loc; 00193 } 00194 00195 /** 00196 * Return reference of a packet location 00197 * @arg loc packet location object. 00198 */ 00199 void rtnl_pktloc_put(struct rtnl_pktloc *loc) 00200 { 00201 if (!loc) 00202 return; 00203 00204 loc->refcnt--; 00205 if (loc->refcnt <= 0) 00206 rtnl_pktloc_free(loc); 00207 } 00208 00209 /** 00210 * Add a packet location to the hash table 00211 * @arg loc packet location object 00212 * 00213 * @return 0 on success or a negative error code. 00214 */ 00215 int rtnl_pktloc_add(struct rtnl_pktloc *loc) 00216 { 00217 struct rtnl_pktloc *l; 00218 00219 if (__pktloc_lookup(loc->name, &l) == 0) { 00220 rtnl_pktloc_put(l); 00221 return -NLE_EXIST; 00222 } 00223 00224 NL_DBG(2, "New packet location entry \"%s\" align=%u layer=%u " 00225 "offset=%u mask=%#x shift=%u refnt=%u\n", 00226 loc->name, loc->align, loc->layer, loc->offset, 00227 loc->mask, loc->shift, loc->refcnt); 00228 00229 nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]); 00230 00231 return 0; 00232 } 00233 00234 void rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *), void *arg) 00235 { 00236 struct rtnl_pktloc *loc; 00237 int i; 00238 00239 /* ignore errors */ 00240 read_pktlocs(); 00241 00242 for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) 00243 nl_list_for_each_entry(loc, &pktloc_name_ht[i], list) 00244 cb(loc, arg); 00245 } 00246 00247 static int __init pktloc_init(void) 00248 { 00249 int i; 00250 00251 for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) 00252 nl_init_list_head(&pktloc_name_ht[i]); 00253 00254 return 0; 00255 } 00256 00257 /** @} */