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