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