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 /** @} */
Dump object briefly on one line.
Definition: types.h:22
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
void nlmsg_free(struct nl_msg *msg)
Release a reference from an netlink message.
Definition: msg.c:565
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
int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind)
Define the type of traffic control object.
Definition: tc.c:530
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
Definition: msg.c:107
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
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
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
Definition: object.c:205
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
struct nl_data * nl_data_alloc_attr(const struct nlattr *nla)
Allocate abstract data object based on netlink attribute.
Definition: data.c:85
Dump all attributes but no statistics.
Definition: types.h:23
void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link)
Set link of traffic control object.
Definition: tc.c:311
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:966
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:253
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:56
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
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:121
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition: attr.c:132
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
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
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1082
int rtnl_act_change(struct nl_sock *sk, struct rtnl_act *act, int flags)
Change an action.
Definition: act.c:304
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
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition: object.c:216
#define NLA_PUT_STRING(msg, attrtype, value)
Add string attribute to netlink message.
Definition: attr.h:263
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
Definition: msg.c:348
int rtnl_act_add(struct nl_sock *sk, struct rtnl_act *act, int flags)
Add/Update action.
Definition: act.c:262
Dumping parameters.
Definition: types.h:33
int rtnl_act_delete(struct nl_sock *sk, struct rtnl_act *act, int flags)
Delete action.
Definition: act.c:366
Dump all attributes including statistics.
Definition: types.h:24
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
Copy string attribute payload to a buffer.
Definition: attr.c:379
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:903