libnl  3.5.0
cls.c
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * lib/route/classifier.c Classifier
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation version 2.1
8  * of the License.
9  *
10  * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
11  */
12 
13 /**
14  * @ingroup tc
15  * @defgroup cls Classifiers
16  * @{
17  */
18 
19 #include <netlink-private/netlink.h>
20 #include <netlink-private/tc.h>
21 #include <netlink/netlink.h>
22 #include <netlink/utils.h>
23 #include <netlink-private/route/tc-api.h>
24 #include <netlink/route/classifier.h>
25 #include <netlink/route/link.h>
26 
27 /** @cond SKIP */
28 #define CLS_ATTR_PRIO (TCA_ATTR_MAX << 1)
29 #define CLS_ATTR_PROTOCOL (TCA_ATTR_MAX << 2)
30 /** @endcond */
31 
32 static struct nl_object_ops cls_obj_ops;
33 static struct nl_cache_ops rtnl_cls_ops;
34 
35 
36 static int cls_build(struct rtnl_cls *cls, int type, int flags,
37  struct nl_msg **result)
38 {
39  int err, prio, proto;
40  struct tcmsg *tchdr;
41  uint32_t required = TCA_ATTR_IFINDEX;
42 
43  if ((cls->ce_mask & required) != required) {
44  APPBUG("ifindex must be specified");
45  return -NLE_MISSING_ATTR;
46  }
47 
48  err = rtnl_tc_msg_build(TC_CAST(cls), type, flags, result);
49  if (err < 0)
50  return err;
51 
52  tchdr = nlmsg_data(nlmsg_hdr(*result));
53  prio = rtnl_cls_get_prio(cls);
54  proto = rtnl_cls_get_protocol(cls);
55  tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto));
56 
57  return 0;
58 }
59 
60 /**
61  * @name Allocation/Freeing
62  * @{
63  */
64 
65 struct rtnl_cls *rtnl_cls_alloc(void)
66 {
67  struct rtnl_tc *tc;
68 
69  tc = TC_CAST(nl_object_alloc(&cls_obj_ops));
70  if (tc)
71  tc->tc_type = RTNL_TC_TYPE_CLS;
72 
73  return (struct rtnl_cls *) tc;
74 }
75 
76 void rtnl_cls_put(struct rtnl_cls *cls)
77 {
78  nl_object_put((struct nl_object *) cls);
79 }
80 
81 /** @} */
82 
83 /**
84  * @name Attributes
85  * @{
86  */
87 
88 void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio)
89 {
90  cls->c_prio = prio;
91  cls->ce_mask |= CLS_ATTR_PRIO;
92 }
93 
94 uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls)
95 {
96  if (cls->ce_mask & CLS_ATTR_PRIO)
97  return cls->c_prio;
98  else
99  return 0;
100 }
101 
102 void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol)
103 {
104  cls->c_protocol = protocol;
105  cls->ce_mask |= CLS_ATTR_PROTOCOL;
106 }
107 
108 uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls)
109 {
110  if (cls->ce_mask & CLS_ATTR_PROTOCOL)
111  return cls->c_protocol;
112  else
113  return ETH_P_ALL;
114 }
115 
116 /** @} */
117 
118 
119 /**
120  * @name Addition/Modification/Deletion
121  * @{
122  */
123 
124 /**
125  * Build a netlink message requesting the addition of a classifier
126  * @arg cls Classifier to add
127  * @arg flags Additional netlink message flags
128  * @arg result Pointer to store resulting netlink message
129  *
130  * The behaviour of this function is identical to rtnl_cls_add() with
131  * the exception that it will not send the message but return it int the
132  * provided return pointer instead.
133  *
134  * @see rtnl_cls_add()
135  *
136  * @return 0 on success or a negative error code.
137  */
138 int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags,
139  struct nl_msg **result)
140 {
141  if (!(flags & NLM_F_CREATE) && !(cls->ce_mask & CLS_ATTR_PRIO)) {
142  APPBUG("prio must be specified if not a new classifier");
143  return -NLE_MISSING_ATTR;
144  }
145 
146  return cls_build(cls, RTM_NEWTFILTER, flags, result);
147 }
148 
149 /**
150  * Add/Update classifier
151  * @arg sk Netlink socket
152  * @arg cls Classifier to add/update
153  * @arg flags Additional netlink message flags
154  *
155  * Builds a \c RTM_NEWTFILTER netlink message requesting the addition
156  * of a new classifier and sends the message to the kernel. The
157  * configuration of the classifier is derived from the attributes of
158  * the specified traffic class.
159  *
160  * The following flags may be specified:
161  * - \c NLM_F_CREATE: Create classifier if it does not exist,
162  * otherwise -NLE_OBJ_NOTFOUND is returned.
163  * - \c NLM_F_EXCL: Return -NLE_EXISTS if a classifier with
164  * matching handle exists already.
165  *
166  * Existing classifiers with matching handles will be updated, unless
167  * the flag \c NLM_F_EXCL is specified. If no matching classifier
168  * exists, it will be created if the flag \c NLM_F_CREATE is set,
169  * otherwise the error -NLE_OBJ_NOTFOUND is returned.
170  *
171  * If the parent qdisc does not support classes, the error
172  * \c NLE_OPNOTSUPP is returned.
173  *
174  * After sending, the function will wait for the ACK or an eventual
175  * error message to be received and will therefore block until the
176  * operation has been completed.
177  *
178  * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
179  * this function to return immediately after sending. In this case,
180  * it is the responsibility of the caller to handle any error
181  * messages returned.
182  *
183  * @return 0 on success or a negative error code.
184  */
185 int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
186 {
187  struct nl_msg *msg;
188  int err;
189 
190  if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0)
191  return err;
192 
193  return nl_send_sync(sk, msg);
194 }
195 
196 /**
197  * Build a netlink message to change classifier attributes
198  * @arg cls classifier to change
199  * @arg flags additional netlink message flags
200  * @arg result Pointer to store resulting message.
201  *
202  * Builds a new netlink message requesting a change of a neigh
203  * attributes. The netlink message header isn't fully equipped with
204  * all relevant fields and must thus be sent out via nl_send_auto_complete()
205  * or supplemented as needed.
206  *
207  * @return 0 on success or a negative error code.
208  */
209 int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags,
210  struct nl_msg **result)
211 {
212  return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result);
213 }
214 
215 /**
216  * Change a classifier
217  * @arg sk Netlink socket.
218  * @arg cls classifier to change
219  * @arg flags additional netlink message flags
220  *
221  * Builds a netlink message by calling rtnl_cls_build_change_request(),
222  * sends the request to the kernel and waits for the next ACK to be
223  * received and thus blocks until the request has been processed.
224  *
225  * @return 0 on sucess or a negative error if an error occured.
226  */
227 int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
228 {
229  struct nl_msg *msg;
230  int err;
231 
232  if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0)
233  return err;
234 
235  return nl_send_sync(sk, msg);
236 }
237 
238 /**
239  * Build netlink message requesting the deletion of a classifier
240  * @arg cls Classifier to delete
241  * @arg flags Additional netlink message flags
242  * @arg result Pointer to store resulting netlink message
243  *
244  * The behaviour of this function is identical to rtnl_cls_delete() with
245  * the exception that it will not send the message but return it in the
246  * provided return pointer instead.
247  *
248  * @see rtnl_cls_delete()
249  *
250  * @return 0 on success or a negative error code.
251  */
252 int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
253  struct nl_msg **result)
254 {
255  uint32_t required = CLS_ATTR_PRIO;
256 
257  if ((cls->ce_mask & required) != required) {
258  APPBUG("prio must be specified");
259  return -NLE_MISSING_ATTR;
260  }
261 
262  return cls_build(cls, RTM_DELTFILTER, flags, result);
263 }
264 
265 /**
266  * Delete classifier
267  * @arg sk Netlink socket
268  * @arg cls Classifier to delete
269  * @arg flags Additional netlink message flags
270  *
271  * Builds a \c RTM_DELTFILTER netlink message requesting the deletion
272  * of a classifier and sends the message to the kernel.
273  *
274  * The message is constructed out of the following attributes:
275  * - \c ifindex (required)
276  * - \c prio (required)
277  * - \c protocol (required)
278  * - \c handle (required)
279  * - \c parent (optional, if not specified parent equals root-qdisc)
280  * - \c kind (optional, must match if provided)
281  *
282  * All other classifier attributes including all class type specific
283  * attributes are ignored.
284  *
285  * After sending, the function will wait for the ACK or an eventual
286  * error message to be received and will therefore block until the
287  * operation has been completed.
288  *
289  * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
290  * this function to return immediately after sending. In this case,
291  * it is the responsibility of the caller to handle any error
292  * messages returned.
293  *
294  * @return 0 on success or a negative error code.
295  */
296 int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
297 {
298  struct nl_msg *msg;
299  int err;
300 
301  if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0)
302  return err;
303 
304  return nl_send_sync(sk, msg);
305 }
306 
307 /** @} */
308 
309 /**
310  * @name Cache Related Functions
311  * @{
312  */
313 
314 /**
315  * Allocate a cache and fill it with all configured classifiers
316  * @arg sk Netlink socket
317  * @arg ifindex Interface index of the network device
318  * @arg parent Parent qdisc/traffic class class
319  * @arg result Pointer to store the created cache
320  *
321  * Allocates a new classifier cache and fills it with a list of all
322  * configured classifier attached to the specified parent qdisc/traffic
323  * class on the specified network device. Release the cache with
324  * nl_cache_free().
325  *
326  * @return 0 on success or a negative error code.
327  */
328 int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent,
329  struct nl_cache **result)
330 {
331  struct nl_cache * cache;
332  int err;
333 
334  if (!(cache = nl_cache_alloc(&rtnl_cls_ops)))
335  return -NLE_NOMEM;
336 
337  cache->c_iarg1 = ifindex;
338  cache->c_iarg2 = parent;
339 
340  if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
341  nl_cache_free(cache);
342  return err;
343  }
344 
345  *result = cache;
346  return 0;
347 }
348 
349 /**
350  * Set interface index and parent handle for classifier cache.
351  * @arg cache Pointer to cache
352  * @arg parent Parent qdisc/traffic class class
353  *
354  * Set the interface index and parent handle of a classifier cache.
355  * This is useful for reusing some existed classifier cache to reduce
356  * the overhead introduced by memory allocation.
357  *
358  * @return void.
359  */
360 void rtnl_cls_cache_set_tc_params(struct nl_cache *cache,
361  int ifindex, uint32_t parent)
362 {
363  cache->c_iarg1 = ifindex;
364  cache->c_iarg2 = parent;
365 }
366 
367 /** @} */
368 
369 static void cls_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p)
370 {
371  struct rtnl_cls *cls = (struct rtnl_cls *) tc;
372  char buf[32];
373 
374  nl_dump(p, " prio %u protocol %s", cls->c_prio,
375  nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf)));
376 }
377 
378 static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
379  struct nlmsghdr *nlh, struct nl_parser_param *pp)
380 {
381  struct rtnl_cls *cls;
382  int err;
383 
384  if (!(cls = rtnl_cls_alloc()))
385  return -NLE_NOMEM;
386 
387  if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(cls))) < 0)
388  goto errout;
389 
390  cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
391  if (cls->c_prio)
392  cls->ce_mask |= CLS_ATTR_PRIO;
393  cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
394  if (cls->c_protocol)
395  cls->ce_mask |= CLS_ATTR_PROTOCOL;
396 
397  err = pp->pp_cb(OBJ_CAST(cls), pp);
398 errout:
399  rtnl_cls_put(cls);
400 
401  return err;
402 }
403 
404 static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk)
405 {
406  struct tcmsg tchdr = {
407  .tcm_family = AF_UNSPEC,
408  .tcm_ifindex = cache->c_iarg1,
409  .tcm_parent = cache->c_iarg2,
410  };
411 
412  return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
413  sizeof(tchdr));
414 }
415 
416 static struct rtnl_tc_type_ops cls_ops = {
417  .tt_type = RTNL_TC_TYPE_CLS,
418  .tt_dump_prefix = "cls",
419  .tt_dump = {
420  [NL_DUMP_LINE] = cls_dump_line,
421  },
422 };
423 
424 static struct nl_cache_ops rtnl_cls_ops = {
425  .co_name = "route/cls",
426  .co_hdrsize = sizeof(struct tcmsg),
427  .co_msgtypes = {
428  { RTM_NEWTFILTER, NL_ACT_NEW, "new" },
429  { RTM_DELTFILTER, NL_ACT_DEL, "del" },
430  { RTM_GETTFILTER, NL_ACT_GET, "get" },
431  END_OF_MSGTYPES_LIST,
432  },
433  .co_protocol = NETLINK_ROUTE,
434  .co_groups = tc_groups,
435  .co_request_update = cls_request_update,
436  .co_msg_parser = cls_msg_parser,
437  .co_obj_ops = &cls_obj_ops,
438 };
439 
440 static struct nl_object_ops cls_obj_ops = {
441  .oo_name = "route/cls",
442  .oo_size = sizeof(struct rtnl_cls),
443  .oo_free_data = rtnl_tc_free_data,
444  .oo_clone = rtnl_tc_clone,
445  .oo_dump = {
446  [NL_DUMP_LINE] = rtnl_tc_dump_line,
447  [NL_DUMP_DETAILS] = rtnl_tc_dump_details,
448  [NL_DUMP_STATS] = rtnl_tc_dump_stats,
449  },
450  .oo_compare = rtnl_tc_compare,
451  .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
452 };
453 
454 static void __init cls_init(void)
455 {
456  rtnl_tc_type_register(&cls_ops);
457  nl_cache_mngt_register(&rtnl_cls_ops);
458 }
459 
460 static void __exit cls_exit(void)
461 {
462  nl_cache_mngt_unregister(&rtnl_cls_ops);
463  rtnl_tc_type_unregister(&cls_ops);
464 }
465 
466 /** @} */
int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
Change a classifier.
Definition: cls.c:227
Dump object briefly on one line.
Definition: types.h:22
int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result)
Allocate a cache and fill it with all configured classifiers.
Definition: cls.c:328
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
Definition: msg.c:107
struct nl_object * nl_object_alloc(struct nl_object_ops *ops)
Allocate a new object of kind specified by the operations handle.
Definition: object.c:55
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition: cache_mngt.c:288
int nl_send_sync(struct nl_sock *sk, struct nl_msg *msg)
Finalize and transmit Netlink message and wait for ACK or error message.
Definition: nl.c:549
int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
Add/Update classifier.
Definition: cls.c:185
int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
Delete classifier.
Definition: cls.c:296
int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags, struct nl_msg **result)
Build a netlink message requesting the addition of a classifier.
Definition: cls.c:138
Dump all attributes but no statistics.
Definition: types.h:23
void nl_cache_free(struct nl_cache *cache)
Free a cache.
Definition: cache.c:409
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:253
void rtnl_cls_cache_set_tc_params(struct nl_cache *cache, int ifindex, uint32_t parent)
Set interface index and parent handle for classifier cache.
Definition: cls.c:360
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:56
struct nlmsghdr * nlmsg_hdr(struct nl_msg *n)
Return actual netlink message.
Definition: msg.c:543
int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags, struct nl_msg **result)
Build netlink message requesting the deletion of a classifier.
Definition: cls.c:252
int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf, size_t size)
Construct and transmit a Netlink message.
Definition: nl.c:581
int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags, struct nl_msg **result)
Build a netlink message to change classifier attributes.
Definition: cls.c:209
int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
(Re)fill a cache with the contents in the kernel.
Definition: cache.c:1041
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition: object.c:216
Dumping parameters.
Definition: types.h:33
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:962
Dump all attributes including statistics.
Definition: types.h:24
struct nl_cache * nl_cache_alloc(struct nl_cache_ops *ops)
Allocate new cache.
Definition: cache.c:184