• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
pktloc_hash(const char * str)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 
rtnl_pktloc_add(struct rtnl_pktloc * loc)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 
rtnl_pktloc_free(struct rtnl_pktloc * loc)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 
read_pktlocs(void)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 			return 0;
95 	}
96 
97 	if (!(fd = fopen(path, "r")))
98 		return -NLE_PKTLOC_FILE;
99 
100 	for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) {
101 		struct rtnl_pktloc *loc, *n;
102 
103 		nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list)
104 			rtnl_pktloc_free(loc);
105 
106 		nl_init_list_head(&pktloc_name_ht[i]);
107 	}
108 
109 	if ((err = pktloc_lex_init(&scanner)) < 0)
110 		return -NLE_FAILURE;
111 
112 	buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner);
113 	pktloc__switch_to_buffer(buf, scanner);
114 
115 	if ((err = pktloc_parse(scanner)) < 0)
116 		return -NLE_FAILURE;
117 
118 	if (scanner)
119 		pktloc_lex_destroy(scanner);
120 
121 	free(path);
122 	last_read = st.st_mtime;
123 
124 	return 0;
125 }
126 
127 /**
128  * Lookup packet location alias
129  * @arg name		Name of packet location.
130  *
131  * Tries to find a matching packet location alias for the supplied
132  * packet location name.
133  *
134  * The file containing the packet location definitions is automatically
135  * re-read if its modification time has changed since the last call.
136  *
137  * @return 0 on success or a negative error code.
138  * @retval NLE_PKTLOC_FILE Unable to open packet location file.
139  * @retval NLE_OBJ_NOTFOUND No matching packet location alias found.
140  */
rtnl_pktloc_lookup(const char * name,struct rtnl_pktloc ** result)141 int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
142 {
143 	struct rtnl_pktloc *loc;
144 	int hash, err;
145 
146 	if ((err = read_pktlocs()) < 0)
147 		return err;
148 
149 	hash = pktloc_hash(name);
150 	nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) {
151 		if (!strcasecmp(loc->name, name)) {
152 			*result = loc;
153 			return 0;
154 		}
155 	}
156 
157 	return -NLE_OBJ_NOTFOUND;
158 }
159 
pktloc_init(void)160 static int __init pktloc_init(void)
161 {
162 	int i;
163 
164 	for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
165 		nl_init_list_head(&pktloc_name_ht[i]);
166 
167 	return 0;
168 }
169