libnl  3.4.0
pktloc.c
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 Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2008-2013 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup tc
14  * @defgroup pktloc Packet Location Aliasing
15  * Packet Location Aliasing
16  *
17  * The packet location aliasing interface eases the use of offset definitions
18  * inside packets by allowing them to be referenced by name. Known positions
19  * of protocol fields are stored in a configuration file and associated with
20  * a name for later reference. The configuration file is distributed with the
21  * library and provides a well defined set of definitions for most common
22  * protocol fields.
23  *
24  * @section pktloc_examples Examples
25  * @par Example 1.1 Looking up a packet location
26  * @code
27  * struct rtnl_pktloc *loc;
28  *
29  * rtnl_pktloc_lookup("ip.src", &loc);
30  * @endcode
31  * @{
32  */
33 
34 #include <netlink-private/netlink.h>
35 #include <netlink-private/tc.h>
36 #include <netlink/netlink.h>
37 #include <netlink/utils.h>
38 #include <netlink/route/pktloc.h>
39 
40 #include "pktloc_syntax.h"
41 #include "pktloc_grammar.h"
42 
43 /** @cond SKIP */
44 #define PKTLOC_NAME_HT_SIZ 256
45 
46 static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ];
47 
48 /* djb2 */
49 static unsigned int pktloc_hash(const char *str)
50 {
51  unsigned long hash = 5381;
52  int c;
53 
54  while ((c = *str++))
55  hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
56 
57  return hash % PKTLOC_NAME_HT_SIZ;
58 }
59 
60 static int __pktloc_lookup(const char *name, struct rtnl_pktloc **result)
61 {
62  struct rtnl_pktloc *loc;
63  int hash;
64 
65  hash = pktloc_hash(name);
66  nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) {
67  if (!strcasecmp(loc->name, name)) {
68  loc->refcnt++;
69  *result = loc;
70  return 0;
71  }
72  }
73 
74  return -NLE_OBJ_NOTFOUND;
75 }
76 
77 extern int pktloc_parse(void *scanner);
78 
79 static void rtnl_pktloc_free(struct rtnl_pktloc *loc)
80 {
81  if (!loc)
82  return;
83 
84  free(loc->name);
85  free(loc);
86 }
87 
88 static int read_pktlocs(void)
89 {
90  YY_BUFFER_STATE buf = NULL;
91  yyscan_t scanner = NULL;
92  static time_t last_read;
93  struct stat st;
94  char *path;
95  int i, err;
96  FILE *fd;
97 
98  if (build_sysconf_path(&path, "pktloc") < 0)
99  return -NLE_NOMEM;
100 
101  /* if stat fails, just try to read the file */
102  if (stat(path, &st) == 0) {
103  /* Don't re-read file if file is unchanged */
104  if (last_read == st.st_mtime) {
105  err = 0;
106  goto errout;
107  }
108  }
109 
110  NL_DBG(2, "Reading packet location file \"%s\"\n", path);
111 
112  if (!(fd = fopen(path, "re"))) {
113  err = -NLE_PKTLOC_FILE;
114  goto errout;
115  }
116 
117  for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) {
118  struct rtnl_pktloc *loc, *n;
119 
120  nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list)
121  rtnl_pktloc_put(loc);
122 
123  nl_init_list_head(&pktloc_name_ht[i]);
124  }
125 
126  if ((err = pktloc_lex_init(&scanner)) < 0) {
127  err = -NLE_FAILURE;
128  goto errout_close;
129  }
130 
131  buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner);
132  pktloc__switch_to_buffer(buf, scanner);
133 
134  if ((err = pktloc_parse(scanner)) != 0) {
135  pktloc__delete_buffer(buf, scanner);
136  err = -NLE_PARSE_ERR;
137  goto errout_scanner;
138  }
139 
140  last_read = st.st_mtime;
141 
142 errout_scanner:
143  pktloc_lex_destroy(scanner);
144 errout_close:
145  fclose(fd);
146 errout:
147  free(path);
148 
149  return err;
150 }
151 
152 /** @endcond */
153 
154 /**
155  * Lookup packet location alias
156  * @arg name Name of packet location.
157  * @arg result Result pointer
158  *
159  * Tries to find a matching packet location alias for the supplied
160  * packet location name.
161  *
162  * The file containing the packet location definitions is automatically
163  * re-read if its modification time has changed since the last call.
164  *
165  * The returned packet location has to be returned after use by calling
166  * rtnl_pktloc_put() in order to allow freeing its memory after the last
167  * user has abandoned it.
168  *
169  * @return 0 on success or a negative error code.
170  * @retval NLE_PKTLOC_FILE Unable to open packet location file.
171  * @retval NLE_OBJ_NOTFOUND No matching packet location alias found.
172  */
173 int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
174 {
175  int err;
176 
177  if ((err = read_pktlocs()) < 0)
178  return err;
179 
180  return __pktloc_lookup(name, result);
181 }
182 
183 /**
184  * Allocate packet location object
185  */
187 {
188  struct rtnl_pktloc *loc;
189 
190  if (!(loc = calloc(1, sizeof(*loc))))
191  return NULL;
192 
193  loc->refcnt = 1;
194  nl_init_list_head(&loc->list);
195 
196  return loc;
197 }
198 
199 /**
200  * Return reference of a packet location
201  * @arg loc packet location object.
202  */
203 void rtnl_pktloc_put(struct rtnl_pktloc *loc)
204 {
205  if (!loc)
206  return;
207 
208  loc->refcnt--;
209  if (loc->refcnt <= 0)
210  rtnl_pktloc_free(loc);
211 }
212 
213 /**
214  * Add a packet location to the hash table
215  * @arg loc packet location object
216  *
217  * @return 0 on success or a negative error code.
218  */
219 int rtnl_pktloc_add(struct rtnl_pktloc *loc)
220 {
221  struct rtnl_pktloc *l;
222 
223  if (__pktloc_lookup(loc->name, &l) == 0) {
224  rtnl_pktloc_put(l);
225  return -NLE_EXIST;
226  }
227 
228  NL_DBG(2, "New packet location entry \"%s\" align=%u layer=%u "
229  "offset=%u mask=%#x shift=%u refnt=%u\n",
230  loc->name, loc->align, loc->layer, loc->offset,
231  loc->mask, loc->shift, loc->refcnt);
232 
233  nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]);
234 
235  return 0;
236 }
237 
238 void rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *), void *arg)
239 {
240  struct rtnl_pktloc *loc;
241  int i;
242 
243  /* ignore errors */
244  read_pktlocs();
245 
246  for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
247  nl_list_for_each_entry(loc, &pktloc_name_ht[i], list)
248  cb(loc, arg);
249 }
250 
251 static int __init pktloc_init(void)
252 {
253  int i;
254 
255  for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
256  nl_init_list_head(&pktloc_name_ht[i]);
257 
258  return 0;
259 }
260 
261 /** @} */
struct rtnl_pktloc * rtnl_pktloc_alloc(void)
Allocate packet location object.
Definition: pktloc.c:186
void rtnl_pktloc_put(struct rtnl_pktloc *loc)
Return reference of a packet location.
Definition: pktloc.c:203
int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
Lookup packet location alias.
Definition: pktloc.c:173
int rtnl_pktloc_add(struct rtnl_pktloc *loc)
Add a packet location to the hash table.
Definition: pktloc.c:219