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
40static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ];
41
42/* djb2 */
43static 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
54static 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
71extern int pktloc_parse(void *scanner);
72
73static void rtnl_pktloc_free(struct rtnl_pktloc *loc)
74{
75 if (!loc)
76 return;
77
78 free(loc->name);
79 free(loc);
80}
81
82static 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
136errout_scanner:
137 pktloc_lex_destroy(scanner);
138errout_close:
139 fclose(fd);
140errout:
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 */
167int 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 */
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 */
214{
215 struct rtnl_pktloc *l;
216
217 if (__pktloc_lookup(loc->name, &l) == 0) {
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
232void 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
245static 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
void rtnl_pktloc_put(struct rtnl_pktloc *loc)
Return reference of a packet location.
Definition: pktloc.c:197
struct rtnl_pktloc * rtnl_pktloc_alloc(void)
Allocate packet location object.
Definition: pktloc.c:180