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