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