libnl 3.7.0
class.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 class Traffic Classes
9 * @{
10 */
11
12#include <netlink-private/netlink.h>
13#include <netlink-private/tc.h>
14#include <netlink/netlink.h>
15#include <netlink-private/route/tc-api.h>
16#include <netlink/route/class.h>
17#include <netlink/route/qdisc.h>
18#include <netlink/route/classifier.h>
19#include <netlink/utils.h>
20
21static struct nl_cache_ops rtnl_class_ops;
22static struct nl_object_ops class_obj_ops;
23
24static void class_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p)
25{
26 struct rtnl_class *class = (struct rtnl_class *) tc;
27 char buf[32];
28
29 if (class->c_info)
30 nl_dump(p, "child-qdisc %s ",
31 rtnl_tc_handle2str(class->c_info, buf, sizeof(buf)));
32}
33
34
35static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
36 struct nlmsghdr *nlh, struct nl_parser_param *pp)
37{
38 struct rtnl_class *class;
39 int err;
40
41 if (!(class = rtnl_class_alloc()))
42 return -NLE_NOMEM;
43
44 if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(class))) < 0)
45 goto errout;
46
47 err = pp->pp_cb(OBJ_CAST(class), pp);
48errout:
49 rtnl_class_put(class);
50
51 return err;
52}
53
54static int class_request_update(struct nl_cache *cache, struct nl_sock *sk)
55{
56 struct tcmsg tchdr = {
57 .tcm_family = AF_UNSPEC,
58 .tcm_ifindex = cache->c_iarg1,
59 };
60
61 return nl_send_simple(sk, RTM_GETTCLASS, NLM_F_DUMP, &tchdr,
62 sizeof(tchdr));
63}
64
65/**
66 * @name Allocation/Freeing
67 * @{
68 */
69
70struct rtnl_class *rtnl_class_alloc(void)
71{
72 struct rtnl_tc *tc;
73
74 tc = TC_CAST(nl_object_alloc(&class_obj_ops));
75 if (tc)
76 tc->tc_type = RTNL_TC_TYPE_CLASS;
77
78 return (struct rtnl_class *) tc;
79}
80
81void rtnl_class_put(struct rtnl_class *class)
82{
83 nl_object_put((struct nl_object *) class);
84}
85
86/** @} */
87
88
89/**
90 * @name Addition/Modification/Deletion
91 * @{
92 */
93
94static int class_build(struct rtnl_class *class, int type, int flags,
95 struct nl_msg **result)
96{
97 uint32_t needed = TCA_ATTR_PARENT | TCA_ATTR_HANDLE;
98
99 if ((class->ce_mask & needed) == needed &&
100 TC_H_MAJ(class->c_parent) && TC_H_MAJ(class->c_handle) &&
101 TC_H_MAJ(class->c_parent) != TC_H_MAJ(class->c_handle)) {
102 APPBUG("TC_H_MAJ(parent) must match TC_H_MAJ(handle)");
103 return -NLE_INVAL;
104 }
105
106 return rtnl_tc_msg_build(TC_CAST(class), type, flags, result);
107}
108
109/**
110 * Build a netlink message requesting the addition of a traffic class
111 * @arg class Traffic class to add
112 * @arg flags Additional netlink message flags
113 * @arg result Pointer to store resulting netlink message
114 *
115 * The behaviour of this function is identical to rtnl_class_add() with
116 * the exception that it will not send the message but return it int the
117 * provided return pointer instead.
118 *
119 * @see rtnl_class_add()
120 *
121 * @return 0 on success or a negative error code.
122 */
123int rtnl_class_build_add_request(struct rtnl_class *class, int flags,
124 struct nl_msg **result)
125{
126 return class_build(class, RTM_NEWTCLASS, flags, result);
127}
128
129/**
130 * Add/Update traffic class
131 * @arg sk Netlink socket
132 * @arg class Traffic class to add
133 * @arg flags Additional netlink message flags
134 *
135 * Builds a \c RTM_NEWTCLASS netlink message requesting the addition
136 * of a new traffic class and sends the message to the kernel. The
137 * configuration of the traffic class is derived from the attributes
138 * of the specified traffic class.
139 *
140 * The following flags may be specified:
141 * - \c NLM_F_CREATE: Create traffic class if it does not exist,
142 * otherwise -NLE_OBJ_NOTFOUND is returned.
143 * - \c NLM_F_EXCL: Return -NLE_EXISTS if a traffic class with
144 * matching handle exists already.
145 *
146 * Existing traffic classes with matching handles will be updated,
147 * unless the flag \c NLM_F_EXCL is specified. If no matching traffic
148 * class exists, it will be created if the flag \c NLM_F_CREATE is set,
149 * otherwise the error -NLE_OBJ_NOTFOUND is returned.
150 *
151 * If the parent qdisc does not support classes, the error
152 * \c NLE_OPNOTSUPP is returned.
153 *
154 * After sending, the function will wait for the ACK or an eventual
155 * error message to be received and will therefore block until the
156 * operation has been completed.
157 *
158 * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
159 * this function to return immediately after sending. In this case,
160 * it is the responsibility of the caller to handle any error
161 * messages returned.
162 *
163 * @return 0 on success or a negative error code.
164 */
165int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags)
166{
167 struct nl_msg *msg;
168 int err;
169
170 if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0)
171 return err;
172
173 return nl_send_sync(sk, msg);
174}
175
176/**
177 * Build netlink message requesting the deletion of a traffic class
178 * @arg class Traffic class to delete
179 * @arg result Pointer to store resulting netlink message
180 *
181 * The behaviour of this function is identical to rtnl_class_delete() with
182 * the exception that it will not send the message but return it in the
183 * provided return pointer instead.
184 *
185 * @see rtnl_class_delete()
186 *
187 * @return 0 on success or a negative error code.
188 */
189int rtnl_class_build_delete_request(struct rtnl_class *class, struct nl_msg **result)
190{
191 struct nl_msg *msg;
192 struct tcmsg tchdr;
193 uint32_t required = TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE;
194
195 if ((class->ce_mask & required) != required) {
196 APPBUG("ifindex and handle must be specified");
197 return -NLE_MISSING_ATTR;
198 }
199
200 if (!(msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0)))
201 return -NLE_NOMEM;
202
203 memset(&tchdr, 0, sizeof(tchdr));
204 tchdr.tcm_family = AF_UNSPEC;
205 tchdr.tcm_ifindex = class->c_ifindex;
206 tchdr.tcm_handle = class->c_handle;
207
208 if (class->ce_mask & TCA_ATTR_PARENT)
209 tchdr.tcm_parent = class->c_parent;
210
211 if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
212 nlmsg_free(msg);
213 return -NLE_MSGSIZE;
214 }
215
216 *result = msg;
217 return 0;
218}
219
220/**
221 * Delete traffic class
222 * @arg sk Netlink socket
223 * @arg class Traffic class to delete
224 *
225 * Builds a \c RTM_DELTCLASS netlink message requesting the deletion
226 * of a traffic class and sends the message to the kernel.
227 *
228 * The message is constructed out of the following attributes:
229 * - \c ifindex and \c handle (required)
230 * - \c parent (optional, must match if provided)
231 *
232 * All other class attributes including all class type specific
233 * attributes are ignored.
234 *
235 * After sending, the function will wait for the ACK or an eventual
236 * error message to be received and will therefore block until the
237 * operation has been completed.
238 *
239 * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
240 * this function to return immediately after sending. In this case,
241 * it is the responsibility of the caller to handle any error
242 * messages returned.
243 *
244 * @return 0 on success or a negative error code.
245 */
246int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class)
247{
248 struct nl_msg *msg;
249 int err;
250
251 if ((err = rtnl_class_build_delete_request(class, &msg)) < 0)
252 return err;
253
254 return nl_send_sync(sk, msg);
255}
256
257/** @} */
258
259/**
260 * @name Leaf Qdisc
261 * @{
262 */
263
264/**
265 * Lookup the leaf qdisc of a traffic class
266 * @arg class the parent traffic class
267 * @arg cache a qdisc cache allocated using rtnl_qdisc_alloc_cache()
268 *
269 * @return Matching Qdisc or NULL if the traffic class has no leaf qdisc
270 */
271struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class,
272 struct nl_cache *cache)
273{
274 struct rtnl_qdisc *leaf;
275
276 if (!class->c_info)
277 return NULL;
278
279 leaf = rtnl_qdisc_get_by_parent(cache, class->c_ifindex,
280 class->c_handle);
281 if (!leaf || leaf->q_handle != class->c_info)
282 return NULL;
283
284 return leaf;
285}
286
287/** @} */
288
289/**
290 * @name Cache Related Functions
291 * @{
292 */
293
294/**
295 * Allocate a cache and fill it with all configured traffic classes
296 * @arg sk Netlink socket
297 * @arg ifindex Interface index of the network device
298 * @arg result Pointer to store the created cache
299 *
300 * Allocates a new traffic class cache and fills it with a list of all
301 * configured traffic classes on a specific network device. Release the
302 * cache with nl_cache_free().
303 *
304 * @return 0 on success or a negative error code.
305 */
306int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex,
307 struct nl_cache **result)
308{
309 struct nl_cache * cache;
310 int err;
311
312 if (!ifindex) {
313 APPBUG("ifindex must be specified");
314 return -NLE_INVAL;
315 }
316
317 if (!(cache = nl_cache_alloc(&rtnl_class_ops)))
318 return -NLE_NOMEM;
319
320 cache->c_iarg1 = ifindex;
321
322 if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
323 nl_cache_free(cache);
324 return err;
325 }
326
327 *result = cache;
328 return 0;
329}
330
331/**
332 * Search traffic class by interface index and handle
333 * @arg cache Traffic class cache
334 * @arg ifindex Interface index
335 * @arg handle ID of traffic class
336 *
337 * Searches a traffic class cache previously allocated with
338 * rtnl_class_alloc_cache() and searches for a traffi class matching
339 * the interface index and handle.
340 *
341 * The reference counter is incremented before returning the traffic
342 * class, therefore the reference must be given back with rtnl_class_put()
343 * after usage.
344 *
345 * @return Traffic class or NULL if no match was found.
346 */
347struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex,
348 uint32_t handle)
349{
350 struct rtnl_class *class;
351
352 if (cache->c_ops != &rtnl_class_ops)
353 return NULL;
354
355 nl_list_for_each_entry(class, &cache->c_items, ce_list) {
356 if (class->c_handle == handle && class->c_ifindex == ifindex) {
357 nl_object_get((struct nl_object *) class);
358 return class;
359 }
360 }
361 return NULL;
362}
363
364/**
365 * Search class by interface index and parent
366 * @arg cache Traffic class cache
367 * @arg ifindex Interface index
368 * @arg parent Handle of parent qdisc
369 *
370 * Searches a class cache previously allocated with rtnl_class_alloc_cache()
371 * and searches for a class matching the interface index and parent qdisc.
372 *
373 * The reference counter is incremented before returning the class, therefore
374 * the reference must be given back with rtnl_class_put() after usage.
375 *
376 * @return pointer to class inside the cache or NULL if no match was found.
377 */
378struct rtnl_class *rtnl_class_get_by_parent(struct nl_cache *cache, int ifindex,
379 uint32_t parent)
380{
381 struct rtnl_class *class;
382
383 if (cache->c_ops != &rtnl_class_ops)
384 return NULL;
385
386 nl_list_for_each_entry(class, &cache->c_items, ce_list) {
387 if (class->c_parent == parent && class->c_ifindex == ifindex) {
388 nl_object_get((struct nl_object *) class);
389 return class;
390 }
391 }
392
393 return NULL;
394}
395
396/** @} */
397
398/**
399 * @name Deprecated Functions
400 * @{
401 */
402
403/**
404 * Call a callback for each child of a class
405 *
406 * @deprecated Use of this function is deprecated, it does not allow
407 * to handle the out of memory situation that can occur.
408 */
409void rtnl_class_foreach_child(struct rtnl_class *class, struct nl_cache *cache,
410 void (*cb)(struct nl_object *, void *), void *arg)
411{
412 struct rtnl_class *filter;
413
414 filter = rtnl_class_alloc();
415 if (!filter)
416 return;
417
418 rtnl_tc_set_parent(TC_CAST(filter), class->c_handle);
419 rtnl_tc_set_ifindex(TC_CAST(filter), class->c_ifindex);
420 rtnl_tc_set_kind(TC_CAST(filter), class->c_kind);
421
422 nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg);
423 rtnl_class_put(filter);
424}
425
426/**
427 * Call a callback for each classifier attached to the class
428 *
429 * @deprecated Use of this function is deprecated, it does not allow
430 * to handle the out of memory situation that can occur.
431 */
432void rtnl_class_foreach_cls(struct rtnl_class *class, struct nl_cache *cache,
433 void (*cb)(struct nl_object *, void *), void *arg)
434{
435 struct rtnl_cls *filter;
436
437 filter = rtnl_cls_alloc();
438 if (!filter)
439 return;
440
441 rtnl_tc_set_ifindex((struct rtnl_tc *) filter, class->c_ifindex);
442 rtnl_tc_set_parent((struct rtnl_tc *) filter, class->c_parent);
443
444 nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
445 rtnl_cls_put(filter);
446}
447
448/** @} */
449
450static struct rtnl_tc_type_ops class_ops = {
451 .tt_type = RTNL_TC_TYPE_CLASS,
452 .tt_dump_prefix = "class",
453 .tt_dump = {
454 [NL_DUMP_DETAILS] = class_dump_details,
455 },
456};
457
458static struct nl_object_ops class_obj_ops = {
459 .oo_name = "route/class",
460 .oo_size = sizeof(struct rtnl_class),
461 .oo_free_data = rtnl_tc_free_data,
462 .oo_clone = rtnl_tc_clone,
463 .oo_dump = {
464 [NL_DUMP_LINE] = rtnl_tc_dump_line,
465 [NL_DUMP_DETAILS] = rtnl_tc_dump_details,
466 [NL_DUMP_STATS] = rtnl_tc_dump_stats,
467 },
468 .oo_compare = rtnl_tc_compare,
469 .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
470};
471
472static struct nl_cache_ops rtnl_class_ops = {
473 .co_name = "route/class",
474 .co_hdrsize = sizeof(struct tcmsg),
475 .co_msgtypes = {
476 { RTM_NEWTCLASS, NL_ACT_NEW, "new" },
477 { RTM_DELTCLASS, NL_ACT_DEL, "del" },
478 { RTM_GETTCLASS, NL_ACT_GET, "get" },
479 END_OF_MSGTYPES_LIST,
480 },
481 .co_protocol = NETLINK_ROUTE,
482 .co_groups = tc_groups,
483 .co_request_update = &class_request_update,
484 .co_msg_parser = &class_msg_parser,
485 .co_obj_ops = &class_obj_ops,
486};
487
488static void __init class_init(void)
489{
490 rtnl_tc_type_register(&class_ops);
491 nl_cache_mngt_register(&rtnl_class_ops);
492}
493
494static void __exit class_exit(void)
495{
496 nl_cache_mngt_unregister(&rtnl_class_ops);
497 rtnl_tc_type_unregister(&class_ops);
498}
499
500/** @} */
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
void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter, void(*cb)(struct nl_object *, void *), void *arg)
Call a callback on each element of the cache (filtered).
Definition: cache.c:1294
struct nl_cache * nl_cache_alloc(struct nl_cache_ops *ops)
Allocate new cache.
Definition: cache.c:178
struct rtnl_qdisc * rtnl_class_leaf_qdisc(struct rtnl_class *class, struct nl_cache *cache)
Lookup the leaf qdisc of a traffic class.
Definition: class.c:271
int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags)
Add/Update traffic class.
Definition: class.c:165
int rtnl_class_build_delete_request(struct rtnl_class *class, struct nl_msg **result)
Build netlink message requesting the deletion of a traffic class.
Definition: class.c:189
struct rtnl_class * rtnl_class_get_by_parent(struct nl_cache *cache, int ifindex, uint32_t parent)
Search class by interface index and parent.
Definition: class.c:378
int rtnl_class_build_add_request(struct rtnl_class *class, int flags, struct nl_msg **result)
Build a netlink message requesting the addition of a traffic class.
Definition: class.c:123
struct rtnl_class * rtnl_class_get(struct nl_cache *cache, int ifindex, uint32_t handle)
Search traffic class by interface index and handle.
Definition: class.c:347
void rtnl_class_foreach_cls(struct rtnl_class *class, struct nl_cache *cache, void(*cb)(struct nl_object *, void *), void *arg)
Call a callback for each classifier attached to the class.
Definition: class.c:432
int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class)
Delete traffic class.
Definition: class.c:246
int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex, struct nl_cache **result)
Allocate a cache and fill it with all configured traffic classes.
Definition: class.c:306
void rtnl_class_foreach_child(struct rtnl_class *class, struct nl_cache *cache, void(*cb)(struct nl_object *, void *), void *arg)
Call a callback for each child of a class.
Definition: class.c:409
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
Definition: classid.c:103
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
Definition: msg.c:341
void nlmsg_free(struct nl_msg *msg)
Release a reference from an netlink message.
Definition: msg.c:558
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
Definition: msg.c:442
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition: object.c:214
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
Definition: object.c:203
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
struct rtnl_qdisc * rtnl_qdisc_get_by_parent(struct nl_cache *cache, int ifindex, uint32_t parent)
Search qdisc by interface index and parent.
Definition: qdisc.c:381
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
int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind)
Define the type of traffic control object.
Definition: tc.c:523
void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex)
Set interface index of traffic control object.
Definition: tc.c:272
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:50
void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent)
Set the parent identifier of a traffic control object.
Definition: tc.c:501
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