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