libnl 3.5.0

act.c
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * lib/route/act.c Action
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) 2013 Cong Wang <xiyou.wangcong@gmail.com>
11 */
12
13 /**
14 * @ingroup tc
15 * @defgroup act Action
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/link.h>
25 #include <netlink/route/action.h>
26
27
28 static struct nl_object_ops act_obj_ops;
29 static struct nl_cache_ops rtnl_act_ops;
30
31 struct rtnl_act * rtnl_act_next(struct rtnl_act *act)
32 {
33 if (act == NULL) {
34 return NULL;
35 }
36
37 return act->a_next;
38 }
39
40 int rtnl_act_append(struct rtnl_act **head, struct rtnl_act *new)
41 {
42 struct rtnl_act *p_act;
43 int count = 1;
44
45 if (*head == NULL) {
46 *head = new;
47 return 0;
48 }
49
50 p_act = *head;
51 while (p_act->a_next) {
52 ++count;
53 p_act = p_act->a_next;
54 }
55
56 if (count > TCA_ACT_MAX_PRIO)
57 return -NLE_RANGE;
58
59 p_act->a_next = new;
60 return 0;
61 }
62
63 int rtnl_act_remove(struct rtnl_act **head, struct rtnl_act *act)
64 {
65 struct rtnl_act *a, **ap;
66
67 for (ap = head; (a = *ap) != NULL; ap = &a->a_next)
68 if (a == act)
69 break;
70 if (a) {
71 *ap = a->a_next;
72 a->a_next = NULL;
73 return 0;
74 }
75
76 return -NLE_OBJ_NOTFOUND;
77 }
78
79 static int rtnl_act_fill_one(struct nl_msg *msg, struct rtnl_act *act, int order)
80 {
81 struct rtnl_tc *tc = TC_CAST(act);
82 struct rtnl_tc_ops *ops;
83 struct nlattr *nest;
84 int err = -NLE_NOMEM;
85
86 nest = nla_nest_start(msg, order);
87 if (!nest)
88 goto nla_put_failure;
89
90 if (tc->ce_mask & TCA_ATTR_KIND)
91 NLA_PUT_STRING(msg, TCA_ACT_KIND, tc->tc_kind);
92
93 ops = rtnl_tc_get_ops(tc);
94 if (ops && (ops->to_msg_fill || ops->to_msg_fill_raw)) {
95 struct nlattr *opts;
96 void *data = rtnl_tc_data(tc);
97
98 if (ops->to_msg_fill) {
99 if (!(opts = nla_nest_start(msg, TCA_ACT_OPTIONS)))
100 goto nla_put_failure;
101
102 if ((err = ops->to_msg_fill(tc, data, msg)) < 0)
103 goto nla_put_failure;
104
105 nla_nest_end(msg, opts);
106 } else if ((err = ops->to_msg_fill_raw(tc, data, msg)) < 0)
107 goto nla_put_failure;
108 }
109 nla_nest_end(msg, nest);
110 return 0;
111
112 nla_put_failure:
113 return err;
114 }
115
116 int rtnl_act_fill(struct nl_msg *msg, int attrtype, struct rtnl_act *act)
117 {
118 struct rtnl_act *p_act = act;
119 struct nlattr *nest;
120 int err, order = 0;
121
122 nest = nla_nest_start(msg, attrtype);
123 if (!nest)
124 return -NLE_MSGSIZE;
125
126 while (p_act) {
127 err = rtnl_act_fill_one(msg, p_act, ++order);
128 if (err)
129 return err;
130 p_act = p_act->a_next;
131 }
132
133 nla_nest_end(msg, nest);
134 return 0;
135 }
136
137 static int rtnl_act_msg_build(struct rtnl_act *act, int type, int flags,
138 struct nl_msg **result)
139 {
140 struct nl_msg *msg;
141 struct tcamsg tcahdr = {
142 .tca_family = AF_UNSPEC,
143 };
144 int err = -NLE_MSGSIZE;
145
146 msg = nlmsg_alloc_simple(type, flags);
147 if (!msg)
148 return -NLE_NOMEM;
149
150 if (nlmsg_append(msg, &tcahdr, sizeof(tcahdr), NLMSG_ALIGNTO) < 0)
151 goto nla_put_failure;
152
153 err = rtnl_act_fill(msg, TCA_ACT_TAB, act);
154 if (err < 0)
155 goto nla_put_failure;
156
157 *result = msg;
158 return 0;
159
160 nla_put_failure:
161 nlmsg_free(msg);
162 return err;
163 }
164
165 static int act_build(struct rtnl_act *act, int type, int flags,
166 struct nl_msg **result)
167 {
168 int err;
169
170 err = rtnl_act_msg_build(act, type, flags, result);
171 if (err < 0)
172 return err;
173 return 0;
174 }
175
176 /**
177 * @name Allocation/Freeing
178 * @{
179 */
180
181 struct rtnl_act *rtnl_act_alloc(void)
182 {
183 struct rtnl_tc *tc;
184
185 tc = TC_CAST(nl_object_alloc(&act_obj_ops));
186 if (tc)
187 tc->tc_type = RTNL_TC_TYPE_ACT;
188
189 return (struct rtnl_act *) tc;
190 }
191
192 void rtnl_act_get(struct rtnl_act *act)
193 {
194 nl_object_get(OBJ_CAST(act));
195 }
196
197 void rtnl_act_put(struct rtnl_act *act)
198 {
199 nl_object_put((struct nl_object *) act);
200 }
201
202 /** @} */
203
204 /**
205 * @name Addition/Modification/Deletion
206 * @{
207 */
208
209 /**
210 * Build a netlink message requesting the addition of an action
211 * @arg act Action to add
212 * @arg flags Additional netlink message flags
213 * @arg result Pointer to store resulting netlink message
214 *
215 * The behaviour of this function is identical to rtnl_act_add() with
216 * the exception that it will not send the message but return it int the
217 * provided return pointer instead.
218 *
219 * @see rtnl_act_add()
220 *
221 * @return 0 on success or a negative error code.
222 */
223 int rtnl_act_build_add_request(struct rtnl_act *act, int flags,
224 struct nl_msg **result)
225 {
226 return act_build(act, RTM_NEWACTION, flags, result);
227 }
228
229 /**
230 * Add/Update action
231 * @arg sk Netlink socket
232 * @arg act Action to add/update
233 * @arg flags Additional netlink message flags
234 *
235 * Builds a \c RTM_NEWACTION netlink message requesting the addition
236 * of a new action and sends the message to the kernel. The
237 * configuration of the action is derived from the attributes of
238 * the specified traffic class.
239 *
240 * The following flags may be specified:
241 * - \c NLM_F_CREATE: Create action if it does not exist,
242 * otherwise -NLE_OBJ_NOTFOUND is returned.
243 * - \c NLM_F_EXCL: Return -NLE_EXISTS if an action with
244 * matching handle exists already.
245 *
246 * Existing actions with matching handles will be updated, unless
247 * the flag \c NLM_F_EXCL is specified. If no matching action
248 * exists, it will be created if the flag \c NLM_F_CREATE is set,
249 * otherwise the error -NLE_OBJ_NOTFOUND is returned.
250 *
251 * After sending, the function will wait for the ACK or an eventual
252 * error message to be received and will therefore block until the
253 * operation has been completed.
254 *
255 * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
256 * this function to return immediately after sending. In this case,
257 * it is the responsibility of the caller to handle any error
258 * messages returned.
259 *
260 * @return 0 on success or a negative error code.
261 */
262 int rtnl_act_add(struct nl_sock *sk, struct rtnl_act *act, int flags)
263 {
264 struct nl_msg *msg;
265 int err;
266
267 if ((err = rtnl_act_build_add_request(act, flags, &msg)) < 0)
268 return err;
269
270 return nl_send_sync(sk, msg);
271 }
272
273 /**
274 * Build a netlink message to change action attributes
275 * @arg act Action to change
276 * @arg flags additional netlink message flags
277 * @arg result Pointer to store resulting message.
278 *
279 * Builds a new netlink message requesting a change of a neigh
280 * attributes. The netlink message header isn't fully equipped with
281 * all relevant fields and must thus be sent out via nl_send_auto_complete()
282 * or supplemented as needed.
283 *
284 * @return 0 on success or a negative error code.
285 */
286 int rtnl_act_build_change_request(struct rtnl_act *act, int flags,
287 struct nl_msg **result)
288 {
289 return act_build(act, RTM_NEWACTION, NLM_F_REPLACE | flags, result);
290 }
291
292 /**
293 * Change an action
294 * @arg sk Netlink socket.
295 * @arg act action to change
296 * @arg flags additional netlink message flags
297 *
298 * Builds a netlink message by calling rtnl_act_build_change_request(),
299 * sends the request to the kernel and waits for the next ACK to be
300 * received and thus blocks until the request has been processed.
301 *
302 * @return 0 on sucess or a negative error if an error occured.
303 */
304 int rtnl_act_change(struct nl_sock *sk, struct rtnl_act *act, int flags)
305 {
306 struct nl_msg *msg;
307 int err;
308
309 if ((err = rtnl_act_build_change_request(act, flags, &msg)) < 0)
310 return err;
311
312 return nl_send_sync(sk, msg);
313 }
314
315 /**
316 * Build netlink message requesting the deletion of an action
317 * @arg act Action to delete
318 * @arg flags Additional netlink message flags
319 * @arg result Pointer to store resulting netlink message
320 *
321 * The behaviour of this function is identical to rtnl_act_delete() with
322 * the exception that it will not send the message but return it in the
323 * provided return pointer instead.
324 *
325 * @see rtnl_act_delete()
326 *
327 * @return 0 on success or a negative error code.
328 */
329 int rtnl_act_build_delete_request(struct rtnl_act *act, int flags,
330 struct nl_msg **result)
331 {
332 return act_build(act, RTM_DELACTION, flags, result);
333 }
334
335 /**
336 * Delete action
337 * @arg sk Netlink socket
338 * @arg act Action to delete
339 * @arg flags Additional netlink message flags
340 *
341 * Builds a \c RTM_DELACTION netlink message requesting the deletion
342 * of an action and sends the message to the kernel.
343 *
344 * The message is constructed out of the following attributes:
345 * - \c ifindex (required)
346 * - \c prio (required)
347 * - \c protocol (required)
348 * - \c handle (required)
349 * - \c parent (optional, if not specified parent equals root-qdisc)
350 * - \c kind (optional, must match if provided)
351 *
352 * All other action attributes including all class type specific
353 * attributes are ignored.
354 *
355 * After sending, the function will wait for the ACK or an eventual
356 * error message to be received and will therefore block until the
357 * operation has been completed.
358 *
359 * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
360 * this function to return immediately after sending. In this case,
361 * it is the responsibility of the caller to handle any error
362 * messages returned.
363 *
364 * @return 0 on success or a negative error code.
365 */
366 int rtnl_act_delete(struct nl_sock *sk, struct rtnl_act *act, int flags)
367 {
368 struct nl_msg *msg;
369 int err;
370
371 if ((err = rtnl_act_build_delete_request(act, flags, &msg)) < 0)
372 return err;
373
374 return nl_send_sync(sk, msg);
375 }
376
377 /** @} */
378
379 static void act_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p)
380 {
381 }
382
383 void rtnl_act_put_all(struct rtnl_act **head)
384 {
385 struct rtnl_act *curr, *next;
386
387 curr = *head;
388 while (curr) {
389 next = curr->a_next;
390 rtnl_act_put(curr);
391 curr = next;
392 }
393 *head = NULL;
394 }
395
396 int rtnl_act_parse(struct rtnl_act **head, struct nlattr *tb)
397 {
398 struct rtnl_act *act;
399 struct rtnl_tc_ops *ops;
400 struct nlattr *tb2[TCA_ACT_MAX + 1];
401 struct nlattr *nla[TCA_ACT_MAX_PRIO + 1];
402 char kind[TCKINDSIZ];
403 int err, i;
404
405 err = nla_parse(nla, TCA_ACT_MAX_PRIO, nla_data(tb),
406 NLMSG_ALIGN(nla_len(tb)), NULL);
407 if (err < 0)
408 return err;
409
410 for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
411 struct rtnl_tc *tc;
412
413 if (nla[i] == NULL)
414 continue;
415
416 act = rtnl_act_alloc();
417 if (!act) {
418 err = -NLE_NOMEM;
419 goto err_free;
420 }
421 tc = TC_CAST(act);
422 err = nla_parse(tb2, TCA_ACT_MAX, nla_data(nla[i]),
423 nla_len(nla[i]), NULL);
424 if (err < 0)
425 goto err_free;
426
427 if (tb2[TCA_ACT_KIND] == NULL) {
428 err = -NLE_MISSING_ATTR;
429 goto err_free;
430 }
431
432 nla_strlcpy(kind, tb2[TCA_ACT_KIND], sizeof(kind));
433 rtnl_tc_set_kind(tc, kind);
434
435 if (tb2[TCA_ACT_OPTIONS]) {
436 tc->tc_opts = nl_data_alloc_attr(tb2[TCA_ACT_OPTIONS]);
437 if (!tc->tc_opts) {
438 err = -NLE_NOMEM;
439 goto err_free;
440 }
441 tc->ce_mask |= TCA_ATTR_OPTS;
442 }
443
444 ops = rtnl_tc_get_ops(tc);
445 if (ops && ops->to_msg_parser) {
446 void *data = rtnl_tc_data(tc);
447
448 if (!data) {
449 err = -NLE_NOMEM;
450 goto err_free;
451 }
452
453 err = ops->to_msg_parser(tc, data);
454 if (err < 0)
455 goto err_free;
456 }
457 err = rtnl_act_append(head, act);
458 if (err < 0)
459 goto err_free;
460 }
461 return 0;
462
463 err_free:
464 rtnl_act_put (act);
465 rtnl_act_put_all(head);
466
467 return err;
468 }
469
470 static int rtnl_act_msg_parse(struct nlmsghdr *n, struct rtnl_act **act)
471 {
472 struct rtnl_tc *tc = TC_CAST(*act);
473 struct nl_cache *link_cache;
474 struct nlattr *tb[TCAA_MAX + 1];
475 struct tcamsg *tm;
476 int err;
477
478 tc->ce_msgtype = n->nlmsg_type;
479
480 err = nlmsg_parse(n, sizeof(*tm), tb, TCAA_MAX, NULL);
481 if (err < 0)
482 return err;
483
484 tm = nlmsg_data(n);
485 tc->tc_family = tm->tca_family;
486
487 if (tb[TCA_ACT_TAB] == NULL)
488 return -NLE_MISSING_ATTR;
489
490 err = rtnl_act_parse(act, tb[TCA_ACT_TAB]);
491 if (err < 0)
492 return err;
493
494 if ((link_cache = __nl_cache_mngt_require("route/link"))) {
495 struct rtnl_link *link;
496
497 if ((link = rtnl_link_get(link_cache, tc->tc_ifindex))) {
498 rtnl_tc_set_link(tc, link);
499
500 /* rtnl_tc_set_link incs refcnt */
501 rtnl_link_put(link);
502 }
503 }
504
505 return 0;
506 }
507 static int act_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
508 struct nlmsghdr *nlh, struct nl_parser_param *pp)
509 {
510 struct rtnl_act *act, *p_act;
511 int err;
512
513 if (!(act = rtnl_act_alloc()))
514 return -NLE_NOMEM;
515
516 if ((err = rtnl_act_msg_parse(nlh, &act)) < 0)
517 goto errout;
518
519 p_act = act;
520 while(p_act) {
521 err = pp->pp_cb(OBJ_CAST(act), pp);
522 if (err)
523 break;
524 p_act = p_act->a_next;
525 }
526 errout:
527 rtnl_act_put(act);
528
529 return err;
530 }
531
532 static int act_request_update(struct nl_cache *cache, struct nl_sock *sk)
533 {
534 struct tcamsg tcahdr = {
535 .tca_family = AF_UNSPEC,
536 };
537
538 return nl_send_simple(sk, RTM_GETACTION, NLM_F_DUMP, &tcahdr,
539 sizeof(tcahdr));
540 }
541
542 static struct rtnl_tc_type_ops act_ops = {
543 .tt_type = RTNL_TC_TYPE_ACT,
544 .tt_dump_prefix = "act",
545 .tt_dump = {
546 [NL_DUMP_LINE] = act_dump_line,
547 },
548 };
549
550 static struct nl_cache_ops rtnl_act_ops = {
551 .co_name = "route/act",
552 .co_hdrsize = sizeof(struct tcmsg),
553 .co_msgtypes = {
554 { RTM_NEWACTION, NL_ACT_NEW, "new" },
555 { RTM_DELACTION, NL_ACT_DEL, "del" },
556 { RTM_GETACTION, NL_ACT_GET, "get" },
557 END_OF_MSGTYPES_LIST,
558 },
559 .co_protocol = NETLINK_ROUTE,
560 .co_request_update = act_request_update,
561 .co_msg_parser = act_msg_parser,
562 .co_obj_ops = &act_obj_ops,
563 };
564
565 static struct nl_object_ops act_obj_ops = {
566 .oo_name = "route/act",
567 .oo_size = sizeof(struct rtnl_act),
568 .oo_free_data = rtnl_tc_free_data,
569 .oo_clone = rtnl_tc_clone,
570 .oo_dump = {
571 [NL_DUMP_LINE] = rtnl_tc_dump_line,
572 [NL_DUMP_DETAILS] = rtnl_tc_dump_details,
573 [NL_DUMP_STATS] = rtnl_tc_dump_stats,
574 },
575 .oo_compare = rtnl_tc_compare,
576 .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
577 };
578
579 static void __init act_init(void)
580 {
581 rtnl_tc_type_register(&act_ops);
582 nl_cache_mngt_register(&rtnl_act_ops);
583 }
584
585 static void __exit act_exit(void)
586 {
587 nl_cache_mngt_unregister(&rtnl_act_ops);
588 rtnl_tc_type_unregister(&act_ops);
589 }
590
591 /** @} */
NL_DUMP_LINE
Dump object briefly on one line.
Definition: types.h:22
nla_parse
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, const struct nla_policy *policy)
Create attribute index based on a stream of attributes.
Definition: attr.c:243
nlmsg_free
void nlmsg_free(struct nl_msg *msg)
Release a reference from an netlink message.
Definition: msg.c:565
nlmsg_parse
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy)
parse attributes of a netlink message
Definition: msg.c:215
rtnl_tc_set_kind
int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind)
Define the type of traffic control object.
Definition: tc.c:530
nlmsg_data
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
Definition: msg.c:107
rtnl_act_build_add_request
int rtnl_act_build_add_request(struct rtnl_act *act, int flags, struct nl_msg **result)
Build a netlink message requesting the addition of an action.
Definition: act.c:223
rtnl_link_get
struct rtnl_link * rtnl_link_get(struct nl_cache *cache, int ifindex)
Lookup link in cache by interface index.
Definition: link.c:1305
nl_object_alloc
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
nl_cache_mngt_unregister
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition: cache_mngt.c:288
nl_object_get
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
Definition: object.c:205
nl_send_sync
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
nl_data_alloc_attr
struct nl_data * nl_data_alloc_attr(const struct nlattr *nla)
Allocate abstract data object based on netlink attribute.
Definition: data.c:85
rtnl_link
Link object.
NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition: types.h:23
rtnl_tc_set_link
void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link)
Set link of traffic control object.
Definition: tc.c:311
nla_nest_end
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:966
nl_cache_mngt_register
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:253
TC_CAST
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:56
rtnl_act_build_change_request
int rtnl_act_build_change_request(struct rtnl_act *act, int flags, struct nl_msg **result)
Build a netlink message to change action attributes.
Definition: act.c:286
nla_data
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:121
nla_len
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition: attr.c:132
rtnl_act_build_delete_request
int rtnl_act_build_delete_request(struct rtnl_act *act, int flags, struct nl_msg **result)
Build netlink message requesting the deletion of an action.
Definition: act.c:329
nl_send_simple
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
rtnl_tc_data
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1082
rtnl_act_change
int rtnl_act_change(struct nl_sock *sk, struct rtnl_act *act, int flags)
Change an action.
Definition: act.c:304
nlmsg_append
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:449
nl_object_put
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition: object.c:216
NLA_PUT_STRING
#define NLA_PUT_STRING(msg, attrtype, value)
Add string attribute to netlink message.
Definition: attr.h:263
nlmsg_alloc_simple
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
Definition: msg.c:348
rtnl_act_add
int rtnl_act_add(struct nl_sock *sk, struct rtnl_act *act, int flags)
Add/Update action.
Definition: act.c:262
nl_dump_params
Dumping parameters.
Definition: types.h:33
rtnl_link_put
void rtnl_link_put(struct rtnl_link *link)
Return a link object reference.
Definition: link.c:1940
rtnl_act_delete
int rtnl_act_delete(struct nl_sock *sk, struct rtnl_act *act, int flags)
Delete action.
Definition: act.c:366
NL_DUMP_STATS
Dump all attributes including statistics.
Definition: types.h:24
nla_strlcpy
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
Copy string attribute payload to a buffer.
Definition: attr.c:379
nla_nest_start
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:903