1/*
2 * lib/route/classifier.c       Classifier
3 *
4 *	This library is free software; you can redistribute it and/or
5 *	modify it under the terms of the GNU Lesser General Public
6 *	License as published by the Free Software Foundation version 2.1
7 *	of the License.
8 *
9 * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
10 */
11
12/**
13 * @ingroup tc
14 * @defgroup cls Classifiers
15 *
16 * @par Classifier Identification
17 * - protocol
18 * - priority
19 * - parent
20 * - interface
21 * - kind
22 * - handle
23 *
24 * @{
25 */
26
27#include <netlink-local.h>
28#include <netlink-tc.h>
29#include <netlink/netlink.h>
30#include <netlink/utils.h>
31#include <netlink/route/tc.h>
32#include <netlink/route/classifier.h>
33#include <netlink/route/classifier-modules.h>
34#include <netlink/route/link.h>
35
36static struct nl_cache_ops rtnl_cls_ops;
37
38static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
39			  struct nlmsghdr *nlh, struct nl_parser_param *pp)
40{
41	struct rtnl_cls_ops *cops;
42	struct rtnl_cls *cls;
43	int err;
44
45	cls = rtnl_cls_alloc();
46	if (!cls) {
47		err = -NLE_NOMEM;
48		goto errout;
49	}
50	cls->ce_msgtype = nlh->nlmsg_type;
51
52	err = tca_msg_parser(nlh, (struct rtnl_tca *) cls);
53	if (err < 0)
54		goto errout_free;
55
56	cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
57	cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
58
59	cops = rtnl_cls_lookup_ops(cls);
60	if (cops && cops->co_msg_parser && (err = cops->co_msg_parser(cls)) < 0)
61		goto errout_free;
62
63	err = pp->pp_cb((struct nl_object *) cls, pp);
64errout_free:
65	rtnl_cls_put(cls);
66errout:
67	return err;
68}
69
70static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk)
71{
72	struct tcmsg tchdr = {
73		.tcm_family = AF_UNSPEC,
74		.tcm_ifindex = cache->c_iarg1,
75		.tcm_parent = cache->c_iarg2,
76	};
77
78	return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
79			      sizeof(tchdr));
80}
81
82
83static int cls_build(struct rtnl_cls *cls, int type, int flags,
84		     struct nl_msg **result)
85{
86	struct rtnl_cls_ops *cops;
87	int err, prio, proto;
88	struct tcmsg *tchdr;
89
90	err = tca_build_msg((struct rtnl_tca *) cls, type, flags, result);
91	if (err < 0)
92		return err;
93
94	tchdr = nlmsg_data(nlmsg_hdr(*result));
95	prio = rtnl_cls_get_prio(cls);
96	proto = rtnl_cls_get_protocol(cls);
97	tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto));
98
99	cops = rtnl_cls_lookup_ops(cls);
100	if (cops && cops->co_get_opts) {
101		struct nl_msg *opts;
102
103		if (!(opts = nlmsg_alloc())) {
104			err = -NLE_NOMEM;
105			goto errout;
106		}
107
108		if (!(err = cops->co_get_opts(cls, opts)))
109			err = nla_put_nested(*result, TCA_OPTIONS, opts);
110
111		nlmsg_free(opts);
112		if (err < 0)
113			goto errout;
114	}
115
116	return 0;
117errout:
118	nlmsg_free(*result);
119	return err;
120}
121
122/**
123 * @name Classifier Addition/Modification/Deletion
124 * @{
125 */
126
127/**
128 * Build a netlink message to add a new classifier
129 * @arg cls		classifier to add
130 * @arg flags		additional netlink message flags
131 * @arg result		Pointer to store resulting message.
132 *
133 * Builds a new netlink message requesting an addition of a classifier
134 * The netlink message header isn't fully equipped with all relevant
135 * fields and must be sent out via nl_send_auto_complete() or
136 * supplemented as needed. \a classifier must contain the attributes of
137 * the new classifier set via \c rtnl_cls_set_* functions. \a opts
138 * may point to the clsasifier specific options.
139 *
140 * @return 0 on success or a negative error code.
141 */
142int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags,
143			       struct nl_msg **result)
144{
145	return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags, result);
146}
147
148/**
149 * Add a new classifier
150 * @arg sk		Netlink socket.
151 * @arg cls 		classifier to add
152 * @arg flags		additional netlink message flags
153 *
154 * Builds a netlink message by calling rtnl_cls_build_add_request(),
155 * sends the request to the kernel and waits for the next ACK to be
156 * received and thus blocks until the request has been processed.
157 *
158 * @return 0 on sucess or a negative error if an error occured.
159 */
160int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
161{
162	struct nl_msg *msg;
163	int err;
164
165	if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0)
166		return err;
167
168	err = nl_send_auto_complete(sk, msg);
169	nlmsg_free(msg);
170	if (err < 0)
171		return err;
172
173	return nl_wait_for_ack(sk);
174}
175
176/**
177 * Build a netlink message to change classifier attributes
178 * @arg cls		classifier to change
179 * @arg flags		additional netlink message flags
180 * @arg result		Pointer to store resulting message.
181 *
182 * Builds a new netlink message requesting a change of a neigh
183 * attributes. The netlink message header isn't fully equipped with
184 * all relevant fields and must thus be sent out via nl_send_auto_complete()
185 * or supplemented as needed.
186 *
187 * @return 0 on success or a negative error code.
188 */
189int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags,
190				  struct nl_msg **result)
191{
192	return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result);
193}
194
195/**
196 * Change a classifier
197 * @arg sk		Netlink socket.
198 * @arg cls		classifier to change
199 * @arg flags		additional netlink message flags
200 *
201 * Builds a netlink message by calling rtnl_cls_build_change_request(),
202 * sends the request to the kernel and waits for the next ACK to be
203 * received and thus blocks until the request has been processed.
204 *
205 * @return 0 on sucess or a negative error if an error occured.
206 */
207int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
208{
209	struct nl_msg *msg;
210	int err;
211
212	if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0)
213		return err;
214
215	err = nl_send_auto_complete(sk, msg);
216	nlmsg_free(msg);
217	if (err < 0)
218		return err;
219
220	return nl_wait_for_ack(sk);
221}
222
223/**
224 * Build a netlink request message to delete a classifier
225 * @arg cls		classifier to delete
226 * @arg flags		additional netlink message flags
227 * @arg result		Pointer to store resulting message.
228 *
229 * Builds a new netlink message requesting a deletion of a classifier.
230 * The netlink message header isn't fully equipped with all relevant
231 * fields and must thus be sent out via nl_send_auto_complete()
232 * or supplemented as needed.
233 *
234 * @return 0 on success or a negative error code.
235 */
236int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
237				  struct nl_msg **result)
238{
239	return cls_build(cls, RTM_DELTFILTER, flags, result);
240}
241
242
243/**
244 * Delete a classifier
245 * @arg sk		Netlink socket.
246 * @arg cls		classifier to delete
247 * @arg flags		additional netlink message flags
248 *
249 * Builds a netlink message by calling rtnl_cls_build_delete_request(),
250 * sends the request to the kernel and waits for the next ACK to be
251 * received and thus blocks until the request has been processed.
252 *
253 * @return 0 on sucess or a negative error if an error occured.
254 */
255int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
256{
257	struct nl_msg *msg;
258	int err;
259
260	if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0)
261		return err;
262
263	err = nl_send_auto_complete(sk, msg);
264	nlmsg_free(msg);
265	if (err < 0)
266		return err;
267
268	return nl_wait_for_ack(sk);
269}
270
271/** @} */
272
273/**
274 * @name Cache Management
275 * @{
276 */
277
278/**
279 * Build a classifier cache including all classifiers attached to the
280 * specified class/qdisc on eht specified interface.
281 * @arg sk		Netlink socket.
282 * @arg ifindex		interface index of the link the classes are
283 *                      attached to.
284 * @arg parent          parent qdisc/class
285 * @arg result		Pointer to store resulting cache.
286 *
287 * Allocates a new cache, initializes it properly and updates it to
288 * include all classes attached to the specified interface.
289 *
290 * @note The caller is responsible for destroying and freeing the
291 *       cache after using it.
292 * @return 0 on success or a negative error code.
293 */
294int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent,			 struct nl_cache **result)
295{
296	struct nl_cache * cache;
297	int err;
298
299	if (!(cache = nl_cache_alloc(&rtnl_cls_ops)))
300		return -NLE_NOMEM;
301
302	cache->c_iarg1 = ifindex;
303	cache->c_iarg2 = parent;
304
305	if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
306		nl_cache_free(cache);
307		return err;
308	}
309
310	*result = cache;
311	return 0;
312}
313
314/** @} */
315
316static struct nl_cache_ops rtnl_cls_ops = {
317	.co_name		= "route/cls",
318	.co_hdrsize		= sizeof(struct tcmsg),
319	.co_msgtypes		= {
320					{ RTM_NEWTFILTER, NL_ACT_NEW, "new" },
321					{ RTM_DELTFILTER, NL_ACT_DEL, "del" },
322					{ RTM_GETTFILTER, NL_ACT_GET, "get" },
323					END_OF_MSGTYPES_LIST,
324				  },
325	.co_protocol		= NETLINK_ROUTE,
326	.co_request_update	= cls_request_update,
327	.co_msg_parser		= cls_msg_parser,
328	.co_obj_ops		= &cls_obj_ops,
329};
330
331static void __init cls_init(void)
332{
333	nl_cache_mngt_register(&rtnl_cls_ops);
334}
335
336static void __exit cls_exit(void)
337{
338	nl_cache_mngt_unregister(&rtnl_cls_ops);
339}
340
341/** @} */
342