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 (at) 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 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 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 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 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 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 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 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 181 void rtnl_act_get(struct rtnl_act *act) 182 { 183 nl_object_get(OBJ_CAST(act)); 184 } 185 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 368 static void act_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p) 369 { 370 } 371 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 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 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 } 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 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 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 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