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