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