99e51d3fae39845470608ee2787fc3d7766aaa9c
[platform/upstream/libnl2.git] / lib / route / 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 General Public License as
6  *      published by the Free Software Foundation version 2 of the License.
7  *
8  * Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch>
9  */
10
11 /**
12  * @ingroup tc
13  * @defgroup pktloc Packet Location Aliasing
14  * Packet Location Aliasing
15  *
16  * The packet location aliasing interface eases the use of offset definitions
17  * inside packets by allowing them to be referenced by name. Known positions
18  * of protocol fields are stored in a configuration file and associated with
19  * a name for later reference. The configuration file is distributed with the
20  * library and provides a well defined set of definitions for most common
21  * protocol fields.
22  *
23  * @subsection pktloc_examples Examples
24  * @par Example 1.1 Looking up a packet location
25  * @code
26  * struct rtnl_pktloc *loc;
27  *
28  * rtnl_pktloc_lookup("ip.src", &loc);
29  * @endcode
30  * @{
31  */
32
33 #include <netlink-local.h>
34 #include <netlink-tc.h>
35 #include <netlink/netlink.h>
36 #include <netlink/utils.h>
37 #include <netlink/route/pktloc.h>
38
39 #include "pktloc_syntax.h"
40 #include "pktloc_grammar.h"
41
42 /** @cond */
43 #define PKTLOC_NAME_HT_SIZ 256
44
45 static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ];
46
47 /* djb2 */
48 unsigned int pktloc_hash(const char *str)
49 {
50         unsigned long hash = 5381;
51         int c;
52
53         while ((c = *str++))
54                 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
55
56         return hash % PKTLOC_NAME_HT_SIZ;
57 }
58
59
60 void rtnl_pktloc_add(struct rtnl_pktloc *loc)
61 {
62         nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]);
63 }
64
65 extern int pktloc_parse(void *scanner);
66
67 /** @endcond */
68
69 static void rtnl_pktloc_free(struct rtnl_pktloc *loc)
70 {
71         if (!loc)
72                 return;
73
74         free(loc->name);
75         free(loc);
76 }
77
78 static int read_pktlocs(void)
79 {
80         YY_BUFFER_STATE buf;
81         yyscan_t scanner = NULL;
82         static time_t last_read;
83         struct stat st = {0};
84         char *path;
85         int i, err;
86         FILE *fd;
87
88         asprintf(&path, "%s/pktloc", SYSCONFDIR);
89
90         /* if stat fails, just try to read the file */
91         if (stat(path, &st) == 0) {
92                 /* Don't re-read file if file is unchanged */
93                 if (last_read == st.st_mtime) {
94                         err = 0;
95                         goto errout;
96                 }
97         }
98
99         if (!(fd = fopen(path, "r"))) {
100                 err = -NLE_PKTLOC_FILE;
101                 goto errout;
102         }
103
104         for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) {
105                 struct rtnl_pktloc *loc, *n;
106
107                 nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list)
108                         rtnl_pktloc_free(loc);
109
110                 nl_init_list_head(&pktloc_name_ht[i]);
111         }
112
113         if ((err = pktloc_lex_init(&scanner)) < 0) {
114                 err = -NLE_FAILURE;
115                 goto errout_close;
116         }
117
118         buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner);
119         pktloc__switch_to_buffer(buf, scanner);
120
121         if ((err = pktloc_parse(scanner)) < 0) {
122                 err = -NLE_FAILURE;
123                 goto errout_scanner;
124         }
125
126         last_read = st.st_mtime;
127
128 errout_scanner:
129         if (scanner)
130                 pktloc_lex_destroy(scanner);
131 errout_close:
132         fclose(fd);
133 errout:
134         free(path);
135
136         return err;
137 }
138
139 /**
140  * Lookup packet location alias
141  * @arg name            Name of packet location.
142  *
143  * Tries to find a matching packet location alias for the supplied
144  * packet location name.
145  *
146  * The file containing the packet location definitions is automatically
147  * re-read if its modification time has changed since the last call.
148  *
149  * @return 0 on success or a negative error code.
150  * @retval NLE_PKTLOC_FILE Unable to open packet location file.
151  * @retval NLE_OBJ_NOTFOUND No matching packet location alias found.
152  */
153 int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
154 {
155         struct rtnl_pktloc *loc;
156         int hash, err;
157
158         if ((err = read_pktlocs()) < 0)
159                 return err;
160
161         hash = pktloc_hash(name);
162         nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) {
163                 if (!strcasecmp(loc->name, name)) {
164                         *result = loc;
165                         return 0;
166                 }
167         }
168
169         return -NLE_OBJ_NOTFOUND;
170 }
171
172 static int __init pktloc_init(void)
173 {
174         int i;
175
176         for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
177                 nl_init_list_head(&pktloc_name_ht[i]);
178
179         return 0;
180 }