libnl
3.2.3
|
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 Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2008-2011 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup tc 00014 * @defgroup pktloc Packet Location Aliasing 00015 * Packet Location Aliasing 00016 * 00017 * The packet location aliasing interface eases the use of offset definitions 00018 * inside packets by allowing them to be referenced by name. Known positions 00019 * of protocol fields are stored in a configuration file and associated with 00020 * a name for later reference. The configuration file is distributed with the 00021 * library and provides a well defined set of definitions for most common 00022 * protocol fields. 00023 * 00024 * @section pktloc_examples Examples 00025 * @par Example 1.1 Looking up a packet location 00026 * @code 00027 * struct rtnl_pktloc *loc; 00028 * 00029 * rtnl_pktloc_lookup("ip.src", &loc); 00030 * @endcode 00031 * @{ 00032 */ 00033 00034 #include <netlink-local.h> 00035 #include <netlink-tc.h> 00036 #include <netlink/netlink.h> 00037 #include <netlink/utils.h> 00038 #include <netlink/route/pktloc.h> 00039 00040 #include "pktloc_syntax.h" 00041 #include "pktloc_grammar.h" 00042 00043 /** @cond SKIP */ 00044 #define PKTLOC_NAME_HT_SIZ 256 00045 00046 static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ]; 00047 00048 /* djb2 */ 00049 static unsigned int pktloc_hash(const char *str) 00050 { 00051 unsigned long hash = 5381; 00052 int c; 00053 00054 while ((c = *str++)) 00055 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ 00056 00057 return hash % PKTLOC_NAME_HT_SIZ; 00058 } 00059 00060 static int __pktloc_lookup(const char *name, struct rtnl_pktloc **result) 00061 { 00062 struct rtnl_pktloc *loc; 00063 int hash; 00064 00065 hash = pktloc_hash(name); 00066 nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) { 00067 if (!strcasecmp(loc->name, name)) { 00068 loc->refcnt++; 00069 *result = loc; 00070 return 0; 00071 } 00072 } 00073 00074 return -NLE_OBJ_NOTFOUND; 00075 } 00076 00077 extern int pktloc_parse(void *scanner); 00078 00079 static void rtnl_pktloc_free(struct rtnl_pktloc *loc) 00080 { 00081 if (!loc) 00082 return; 00083 00084 free(loc->name); 00085 free(loc); 00086 } 00087 00088 static int read_pktlocs(void) 00089 { 00090 YY_BUFFER_STATE buf = NULL; 00091 yyscan_t scanner = NULL; 00092 static time_t last_read; 00093 struct stat st = {0}; 00094 char *path; 00095 int i, err; 00096 FILE *fd; 00097 00098 if (build_sysconf_path(&path, "pktloc") < 0) 00099 return -NLE_NOMEM; 00100 00101 /* if stat fails, just try to read the file */ 00102 if (stat(path, &st) == 0) { 00103 /* Don't re-read file if file is unchanged */ 00104 if (last_read == st.st_mtime) 00105 return 0; 00106 } 00107 00108 NL_DBG(2, "Reading packet location file \"%s\"\n", path); 00109 00110 if (!(fd = fopen(path, "r"))) { 00111 err = -NLE_PKTLOC_FILE; 00112 goto errout; 00113 } 00114 00115 for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) { 00116 struct rtnl_pktloc *loc, *n; 00117 00118 nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list) 00119 rtnl_pktloc_put(loc); 00120 00121 nl_init_list_head(&pktloc_name_ht[i]); 00122 } 00123 00124 if ((err = pktloc_lex_init(&scanner)) < 0) { 00125 err = -NLE_FAILURE; 00126 goto errout_close; 00127 } 00128 00129 buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner); 00130 pktloc__switch_to_buffer(buf, scanner); 00131 00132 if ((err = pktloc_parse(scanner)) != 0) { 00133 pktloc__delete_buffer(buf, scanner); 00134 err = -NLE_PARSE_ERR; 00135 goto errout_scanner; 00136 } 00137 00138 last_read = st.st_mtime; 00139 00140 errout_scanner: 00141 if (scanner) 00142 pktloc_lex_destroy(scanner); 00143 errout_close: 00144 fclose(fd); 00145 errout: 00146 free(path); 00147 00148 return 0; 00149 } 00150 00151 /** @endcond */ 00152 00153 /** 00154 * Lookup packet location alias 00155 * @arg name Name of packet location. 00156 * @arg result Result pointer 00157 * 00158 * Tries to find a matching packet location alias for the supplied 00159 * packet location name. 00160 * 00161 * The file containing the packet location definitions is automatically 00162 * re-read if its modification time has changed since the last call. 00163 * 00164 * The returned packet location has to be returned after use by calling 00165 * rtnl_pktloc_put() in order to allow freeing its memory after the last 00166 * user has abandoned it. 00167 * 00168 * @return 0 on success or a negative error code. 00169 * @retval NLE_PKTLOC_FILE Unable to open packet location file. 00170 * @retval NLE_OBJ_NOTFOUND No matching packet location alias found. 00171 */ 00172 int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result) 00173 { 00174 int err; 00175 00176 if ((err = read_pktlocs()) < 0) 00177 return err; 00178 00179 return __pktloc_lookup(name, result); 00180 } 00181 00182 /** 00183 * Allocate packet location object 00184 */ 00185 struct rtnl_pktloc *rtnl_pktloc_alloc(void) 00186 { 00187 struct rtnl_pktloc *loc; 00188 00189 if (!(loc = calloc(1, sizeof(*loc)))) 00190 return NULL; 00191 00192 loc->refcnt = 1; 00193 nl_init_list_head(&loc->list); 00194 00195 return loc; 00196 } 00197 00198 /** 00199 * Return reference of a packet location 00200 * @arg loc packet location object. 00201 */ 00202 void rtnl_pktloc_put(struct rtnl_pktloc *loc) 00203 { 00204 if (!loc) 00205 return; 00206 00207 loc->refcnt--; 00208 if (loc->refcnt <= 0) 00209 rtnl_pktloc_free(loc); 00210 } 00211 00212 /** 00213 * Add a packet location to the hash table 00214 * @arg loc packet location object 00215 * 00216 * @return 0 on success or a negative error code. 00217 */ 00218 int rtnl_pktloc_add(struct rtnl_pktloc *loc) 00219 { 00220 struct rtnl_pktloc *l; 00221 00222 if (__pktloc_lookup(loc->name, &l) == 0) { 00223 rtnl_pktloc_put(l); 00224 return -NLE_EXIST; 00225 } 00226 00227 NL_DBG(2, "New packet location entry \"%s\" align=%u layer=%u " 00228 "offset=%u mask=%#x shift=%u refnt=%u\n", 00229 loc->name, loc->align, loc->layer, loc->offset, 00230 loc->mask, loc->shift, loc->refcnt); 00231 00232 nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]); 00233 00234 return 0; 00235 } 00236 00237 void rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *), void *arg) 00238 { 00239 struct rtnl_pktloc *loc; 00240 int i; 00241 00242 /* ignore errors */ 00243 read_pktlocs(); 00244 00245 for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) 00246 nl_list_for_each_entry(loc, &pktloc_name_ht[i], list) 00247 cb(loc, arg); 00248 } 00249 00250 static int __init pktloc_init(void) 00251 { 00252 int i; 00253 00254 for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) 00255 nl_init_list_head(&pktloc_name_ht[i]); 00256 00257 return 0; 00258 } 00259 00260 /** @} */