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