1/* 2 * lib/route/tc.c Traffic Control 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) 2003-2011 Thomas Graf <tgraf@suug.ch> 10 */ 11 12/** 13 * @ingroup rtnl 14 * @defgroup tc Traffic Control 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/route/rtnl.h> 23#include <netlink/route/link.h> 24#include <netlink/route/tc.h> 25#include <netlink-private/route/tc-api.h> 26 27/** @cond SKIP */ 28 29static struct nl_list_head tc_ops_list[__RTNL_TC_TYPE_MAX]; 30static struct rtnl_tc_type_ops *tc_type_ops[__RTNL_TC_TYPE_MAX]; 31 32static struct nla_policy tc_policy[TCA_MAX+1] = { 33 [TCA_KIND] = { .type = NLA_STRING, 34 .maxlen = TCKINDSIZ }, 35 [TCA_STATS] = { .minlen = sizeof(struct tc_stats) }, 36 [TCA_STATS2] = { .type = NLA_NESTED }, 37}; 38 39int tca_parse(struct nlattr **tb, int maxattr, struct rtnl_tc *g, 40 struct nla_policy *policy) 41{ 42 43 if (g->ce_mask & TCA_ATTR_OPTS) 44 return nla_parse(tb, maxattr, 45 (struct nlattr *) g->tc_opts->d_data, 46 g->tc_opts->d_size, policy); 47 else { 48 /* Ugly but tb[] must be in a defined state even if no 49 * attributes can be found. */ 50 memset(tb, 0, sizeof(struct nlattr *) * (maxattr + 1)); 51 return 0; 52 } 53} 54 55static struct nla_policy tc_stats2_policy[TCA_STATS_MAX+1] = { 56 [TCA_STATS_BASIC] = { .minlen = sizeof(struct gnet_stats_basic) }, 57 [TCA_STATS_RATE_EST] = { .minlen = sizeof(struct gnet_stats_rate_est) }, 58 [TCA_STATS_QUEUE] = { .minlen = sizeof(struct gnet_stats_queue) }, 59}; 60 61int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc) 62{ 63 struct nl_cache *link_cache; 64 struct rtnl_tc_ops *ops; 65 struct nlattr *tb[TCA_MAX + 1]; 66 char kind[TCKINDSIZ]; 67 struct tcmsg *tm; 68 int err; 69 70 tc->ce_msgtype = n->nlmsg_type; 71 72 err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy); 73 if (err < 0) 74 return err; 75 76 if (tb[TCA_KIND] == NULL) 77 return -NLE_MISSING_ATTR; 78 79 nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind)); 80 rtnl_tc_set_kind(tc, kind); 81 82 tm = nlmsg_data(n); 83 tc->tc_family = tm->tcm_family; 84 tc->tc_ifindex = tm->tcm_ifindex; 85 tc->tc_handle = tm->tcm_handle; 86 tc->tc_parent = tm->tcm_parent; 87 tc->tc_info = tm->tcm_info; 88 89 tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE| 90 TCA_ATTR_PARENT | TCA_ATTR_INFO); 91 92 if (tb[TCA_OPTIONS]) { 93 tc->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]); 94 if (!tc->tc_opts) 95 return -NLE_NOMEM; 96 tc->ce_mask |= TCA_ATTR_OPTS; 97 } 98 99 if (tb[TCA_STATS2]) { 100 struct nlattr *tbs[TCA_STATS_MAX + 1]; 101 102 err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2], 103 tc_stats2_policy); 104 if (err < 0) 105 return err; 106 107 if (tbs[TCA_STATS_BASIC]) { 108 struct gnet_stats_basic *bs; 109 110 bs = nla_data(tbs[TCA_STATS_BASIC]); 111 tc->tc_stats[RTNL_TC_BYTES] = bs->bytes; 112 tc->tc_stats[RTNL_TC_PACKETS] = bs->packets; 113 } 114 115 if (tbs[TCA_STATS_RATE_EST]) { 116 struct gnet_stats_rate_est *re; 117 118 re = nla_data(tbs[TCA_STATS_RATE_EST]); 119 tc->tc_stats[RTNL_TC_RATE_BPS] = re->bps; 120 tc->tc_stats[RTNL_TC_RATE_PPS] = re->pps; 121 } 122 123 if (tbs[TCA_STATS_QUEUE]) { 124 struct gnet_stats_queue *q; 125 126 q = nla_data(tbs[TCA_STATS_QUEUE]); 127 tc->tc_stats[RTNL_TC_QLEN] = q->qlen; 128 tc->tc_stats[RTNL_TC_BACKLOG] = q->backlog; 129 tc->tc_stats[RTNL_TC_DROPS] = q->drops; 130 tc->tc_stats[RTNL_TC_REQUEUES] = q->requeues; 131 tc->tc_stats[RTNL_TC_OVERLIMITS] = q->overlimits; 132 } 133 134 tc->ce_mask |= TCA_ATTR_STATS; 135 136 if (tbs[TCA_STATS_APP]) { 137 tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]); 138 if (tc->tc_xstats == NULL) 139 return -NLE_NOMEM; 140 } else 141 goto compat_xstats; 142 } else { 143 if (tb[TCA_STATS]) { 144 struct tc_stats *st = nla_data(tb[TCA_STATS]); 145 146 tc->tc_stats[RTNL_TC_BYTES] = st->bytes; 147 tc->tc_stats[RTNL_TC_PACKETS] = st->packets; 148 tc->tc_stats[RTNL_TC_RATE_BPS] = st->bps; 149 tc->tc_stats[RTNL_TC_RATE_PPS] = st->pps; 150 tc->tc_stats[RTNL_TC_QLEN] = st->qlen; 151 tc->tc_stats[RTNL_TC_BACKLOG] = st->backlog; 152 tc->tc_stats[RTNL_TC_DROPS] = st->drops; 153 tc->tc_stats[RTNL_TC_OVERLIMITS]= st->overlimits; 154 155 tc->ce_mask |= TCA_ATTR_STATS; 156 } 157 158compat_xstats: 159 if (tb[TCA_XSTATS]) { 160 tc->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]); 161 if (tc->tc_xstats == NULL) 162 return -NLE_NOMEM; 163 tc->ce_mask |= TCA_ATTR_XSTATS; 164 } 165 } 166 167 ops = rtnl_tc_get_ops(tc); 168 if (ops && ops->to_msg_parser) { 169 void *data = rtnl_tc_data(tc); 170 171 if (!data) 172 return -NLE_NOMEM; 173 174 err = ops->to_msg_parser(tc, data); 175 if (err < 0) 176 return err; 177 } 178 179 if ((link_cache = __nl_cache_mngt_require("route/link"))) { 180 struct rtnl_link *link; 181 182 if ((link = rtnl_link_get(link_cache, tc->tc_ifindex))) { 183 rtnl_tc_set_link(tc, link); 184 185 /* rtnl_tc_set_link incs refcnt */ 186 rtnl_link_put(link); 187 } 188 } 189 190 return 0; 191} 192 193int rtnl_tc_msg_build(struct rtnl_tc *tc, int type, int flags, 194 struct nl_msg **result) 195{ 196 struct nl_msg *msg; 197 struct rtnl_tc_ops *ops; 198 struct tcmsg tchdr = { 199 .tcm_family = AF_UNSPEC, 200 .tcm_ifindex = tc->tc_ifindex, 201 .tcm_handle = tc->tc_handle, 202 .tcm_parent = tc->tc_parent, 203 }; 204 int err = -NLE_MSGSIZE; 205 206 msg = nlmsg_alloc_simple(type, flags); 207 if (!msg) 208 return -NLE_NOMEM; 209 210 if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) 211 goto nla_put_failure; 212 213 if (tc->ce_mask & TCA_ATTR_KIND) 214 NLA_PUT_STRING(msg, TCA_KIND, tc->tc_kind); 215 216 ops = rtnl_tc_get_ops(tc); 217 if (ops && (ops->to_msg_fill || ops->to_msg_fill_raw)) { 218 struct nlattr *opts; 219 void *data = rtnl_tc_data(tc); 220 221 if (ops->to_msg_fill) { 222 if (!(opts = nla_nest_start(msg, TCA_OPTIONS))) 223 goto nla_put_failure; 224 225 if ((err = ops->to_msg_fill(tc, data, msg)) < 0) 226 goto nla_put_failure; 227 228 nla_nest_end(msg, opts); 229 } else if ((err = ops->to_msg_fill_raw(tc, data, msg)) < 0) 230 goto nla_put_failure; 231 } 232 233 *result = msg; 234 return 0; 235 236nla_put_failure: 237 nlmsg_free(msg); 238 return err; 239} 240 241void tca_set_kind(struct rtnl_tc *t, const char *kind) 242{ 243 strncpy(t->tc_kind, kind, sizeof(t->tc_kind) - 1); 244 t->ce_mask |= TCA_ATTR_KIND; 245} 246 247 248/** @endcond */ 249 250/** 251 * @name Attributes 252 * @{ 253 */ 254 255/** 256 * Set interface index of traffic control object 257 * @arg tc traffic control object 258 * @arg ifindex interface index. 259 * 260 * Sets the interface index of a traffic control object. The interface 261 * index defines the network device which this tc object is attached to. 262 * This function will overwrite any network device assigned with previous 263 * calls to rtnl_tc_set_ifindex() or rtnl_tc_set_link(). 264 */ 265void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex) 266{ 267 /* Obsolete possible old link reference */ 268 rtnl_link_put(tc->tc_link); 269 tc->tc_link = NULL; 270 tc->ce_mask &= ~TCA_ATTR_LINK; 271 272 tc->tc_ifindex = ifindex; 273 tc->ce_mask |= TCA_ATTR_IFINDEX; 274} 275 276/** 277 * Return interface index of traffic control object 278 * @arg tc traffic control object 279 */ 280int rtnl_tc_get_ifindex(struct rtnl_tc *tc) 281{ 282 return tc->tc_ifindex; 283} 284 285/** 286 * Set link of traffic control object 287 * @arg tc traffic control object 288 * @arg link link object 289 * 290 * Sets the link of a traffic control object. This function serves 291 * the same purpose as rtnl_tc_set_ifindex() but due to the continued 292 * allowed access to the link object it gives it the possibility to 293 * retrieve sane default values for the the MTU and the linktype. 294 * Always prefer this function over rtnl_tc_set_ifindex() if you can 295 * spare to have an additional link object around. 296 */ 297void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link) 298{ 299 rtnl_link_put(tc->tc_link); 300 301 if (!link) 302 return; 303 if (!link->l_index) 304 BUG(); 305 306 nl_object_get(OBJ_CAST(link)); 307 tc->tc_link = link; 308 tc->tc_ifindex = link->l_index; 309 tc->ce_mask |= TCA_ATTR_LINK | TCA_ATTR_IFINDEX; 310} 311 312/** 313 * Get link of traffic control object 314 * @arg tc traffic control object 315 * 316 * Returns the link of a traffic control object. The link is only 317 * returned if it has been set before via rtnl_tc_set_link() or 318 * if a link cache was available while parsing the tc object. This 319 * function may still return NULL even if an ifindex is assigned to 320 * the tc object. It will _not_ look up the link by itself. 321 * 322 * @note The returned link will have its reference counter incremented. 323 * It is in the responsibility of the caller to return the 324 * reference. 325 * 326 * @return link object or NULL if not set. 327 */ 328struct rtnl_link *rtnl_tc_get_link(struct rtnl_tc *tc) 329{ 330 if (tc->tc_link) { 331 nl_object_get(OBJ_CAST(tc->tc_link)); 332 return tc->tc_link; 333 } 334 335 return NULL; 336} 337 338/** 339 * Set the Maximum Transmission Unit (MTU) of traffic control object 340 * @arg tc traffic control object 341 * @arg mtu largest packet size expected 342 * 343 * Sets the MTU of a traffic control object. Not all traffic control 344 * objects will make use of this but it helps while calculating rate 345 * tables. This value is typically derived directly from the link 346 * the tc object is attached to if the link has been assigned via 347 * rtnl_tc_set_link(). It is usually not necessary to set the MTU 348 * manually, this function is provided to allow overwriting the derived 349 * value. 350 */ 351void rtnl_tc_set_mtu(struct rtnl_tc *tc, uint32_t mtu) 352{ 353 tc->tc_mtu = mtu; 354 tc->ce_mask |= TCA_ATTR_MTU; 355} 356 357/** 358 * Return the MTU of traffic control object 359 * @arg tc traffic control object 360 * 361 * Returns the MTU of a traffic control object which has been set via: 362 * -# User specified value set via rtnl_tc_set_mtu() 363 * -# Dervied from link set via rtnl_tc_set_link() 364 * -# Fall back to default: ethernet = 1500 365 */ 366uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc) 367{ 368 if (tc->ce_mask & TCA_ATTR_MTU) 369 return tc->tc_mtu; 370 else if (tc->ce_mask & TCA_ATTR_LINK) 371 return tc->tc_link->l_mtu; 372 else 373 return 1500; /* default to ethernet */ 374} 375 376/** 377 * Set the Minimum Packet Unit (MPU) of a traffic control object 378 * @arg tc traffic control object 379 * @arg mpu minimum packet size expected 380 * 381 * Sets the MPU of a traffic contorl object. It specifies the minimum 382 * packet size to ever hit this traffic control object. Not all traffic 383 * control objects will make use of this but it helps while calculating 384 * rate tables. 385 */ 386void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu) 387{ 388 tc->tc_mpu = mpu; 389 tc->ce_mask |= TCA_ATTR_MPU; 390} 391 392/** 393 * Return the Minimum Packet Unit (MPU) of a traffic control object 394 * @arg tc traffic control object 395 * 396 * @return The MPU previously set via rtnl_tc_set_mpu() or 0. 397 */ 398uint32_t rtnl_tc_get_mpu(struct rtnl_tc *tc) 399{ 400 return tc->tc_mpu; 401} 402 403/** 404 * Set per packet overhead of a traffic control object 405 * @arg tc traffic control object 406 * @arg overhead overhead per packet in bytes 407 * 408 * Sets the per packet overhead in bytes occuring on the link not seen 409 * by the kernel. This value can be used to correct size calculations 410 * if the packet size on the wire does not match the packet sizes seen 411 * in the network stack. Not all traffic control objects will make use 412 * this but it helps while calculating accurate packet sizes in the 413 * kernel. 414 */ 415void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead) 416{ 417 tc->tc_overhead = overhead; 418 tc->ce_mask |= TCA_ATTR_OVERHEAD; 419} 420 421/** 422 * Return per packet overhead of a traffic control object 423 * @arg tc traffic control object 424 * 425 * @return The overhead previously set by rtnl_tc_set_overhead() or 0. 426 */ 427uint32_t rtnl_tc_get_overhead(struct rtnl_tc *tc) 428{ 429 return tc->tc_overhead; 430} 431 432/** 433 * Set the linktype of a traffic control object 434 * @arg tc traffic control object 435 * @arg type type of link (e.g. ARPHRD_ATM, ARPHRD_ETHER) 436 * 437 * Overwrites the type of link this traffic control object is attached to. 438 * This value is typically derived from the link this tc object is attached 439 * if the link has been assigned via rtnl_tc_set_link(). It is usually not 440 * necessary to set the linktype manually. This function is provided to 441 * allow overwriting the linktype. 442 */ 443void rtnl_tc_set_linktype(struct rtnl_tc *tc, uint32_t type) 444{ 445 tc->tc_linktype = type; 446 tc->ce_mask |= TCA_ATTR_LINKTYPE; 447} 448 449/** 450 * Return the linktype of a traffic control object 451 * @arg tc traffic control object 452 * 453 * Returns the linktype of the link the traffic control object is attached to: 454 * -# User specified value via rtnl_tc_set_linktype() 455 * -# Value derived from link set via rtnl_tc_set_link() 456 * -# Default fall-back: ARPHRD_ETHER 457 */ 458uint32_t rtnl_tc_get_linktype(struct rtnl_tc *tc) 459{ 460 if (tc->ce_mask & TCA_ATTR_LINKTYPE) 461 return tc->tc_linktype; 462 else if (tc->ce_mask & TCA_ATTR_LINK) 463 return tc->tc_link->l_arptype; 464 else 465 return ARPHRD_ETHER; /* default to ethernet */ 466} 467 468/** 469 * Set identifier of traffic control object 470 * @arg tc traffic control object 471 * @arg id unique identifier 472 */ 473void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id) 474{ 475 tc->tc_handle = id; 476 tc->ce_mask |= TCA_ATTR_HANDLE; 477} 478 479/** 480 * Return identifier of a traffic control object 481 * @arg tc traffic control object 482 */ 483uint32_t rtnl_tc_get_handle(struct rtnl_tc *tc) 484{ 485 return tc->tc_handle; 486} 487 488/** 489 * Set the parent identifier of a traffic control object 490 * @arg tc traffic control object 491 * @arg parent identifier of parent traffif control object 492 * 493 */ 494void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent) 495{ 496 tc->tc_parent = parent; 497 tc->ce_mask |= TCA_ATTR_PARENT; 498} 499 500/** 501 * Return parent identifier of a traffic control object 502 * @arg tc traffic control object 503 */ 504uint32_t rtnl_tc_get_parent(struct rtnl_tc *tc) 505{ 506 return tc->tc_parent; 507} 508 509/** 510 * Define the type of traffic control object 511 * @arg tc traffic control object 512 * @arg kind name of the tc object type 513 * 514 * @return 0 on success or a negative error code 515 */ 516int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind) 517{ 518 if (tc->ce_mask & TCA_ATTR_KIND) 519 return -NLE_EXIST; 520 521 strncpy(tc->tc_kind, kind, sizeof(tc->tc_kind) - 1); 522 tc->ce_mask |= TCA_ATTR_KIND; 523 524 /* Force allocation of data */ 525 rtnl_tc_data(tc); 526 527 return 0; 528} 529 530/** 531 * Return kind of traffic control object 532 * @arg tc traffic control object 533 * 534 * @return Kind of traffic control object or NULL if not set. 535 */ 536char *rtnl_tc_get_kind(struct rtnl_tc *tc) 537{ 538 if (tc->ce_mask & TCA_ATTR_KIND) 539 return tc->tc_kind; 540 else 541 return NULL; 542} 543 544/** 545 * Return value of a statistical counter of a traffic control object 546 * @arg tc traffic control object 547 * @arg id identifier of statistical counter 548 * 549 * @return Value of requested statistic counter or 0. 550 */ 551uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id) 552{ 553 if (id < 0 || id > RTNL_TC_STATS_MAX) 554 return 0; 555 556 return tc->tc_stats[id]; 557} 558 559/** @} */ 560 561/** 562 * @name Utilities 563 * @{ 564 */ 565 566/** 567 * Calculate time required to transmit buffer at a specific rate 568 * @arg bufsize Size of buffer to be transmited in bytes. 569 * @arg rate Transmit rate in bytes per second. 570 * 571 * Calculates the number of micro seconds required to transmit a 572 * specific buffer at a specific transmit rate. 573 * 574 * @f[ 575 * txtime=\frac{bufsize}{rate}10^6 576 * @f] 577 * 578 * @return Required transmit time in micro seconds. 579 */ 580int rtnl_tc_calc_txtime(int bufsize, int rate) 581{ 582 double tx_time_secs; 583 584 tx_time_secs = (double) bufsize / (double) rate; 585 586 return tx_time_secs * 1000000.; 587} 588 589/** 590 * Calculate buffer size able to transmit in a specific time and rate. 591 * @arg txtime Available transmit time in micro seconds. 592 * @arg rate Transmit rate in bytes per second. 593 * 594 * Calculates the size of the buffer that can be transmitted in a 595 * specific time period at a specific transmit rate. 596 * 597 * @f[ 598 * bufsize=\frac{{txtime} \times {rate}}{10^6} 599 * @f] 600 * 601 * @return Size of buffer in bytes. 602 */ 603int rtnl_tc_calc_bufsize(int txtime, int rate) 604{ 605 double bufsize; 606 607 bufsize = (double) txtime * (double) rate; 608 609 return bufsize / 1000000.; 610} 611 612/** 613 * Calculate the binary logarithm for a specific cell size 614 * @arg cell_size Size of cell, must be a power of two. 615 * @return Binary logirhtm of cell size or a negative error code. 616 */ 617int rtnl_tc_calc_cell_log(int cell_size) 618{ 619 int i; 620 621 for (i = 0; i < 32; i++) 622 if ((1 << i) == cell_size) 623 return i; 624 625 return -NLE_INVAL; 626} 627 628 629/** @} */ 630 631/** 632 * @name Rate Tables 633 * @{ 634 */ 635 636/* 637 * COPYRIGHT NOTE: 638 * align_to_atm() and adjust_size() derived/coped from iproute2 source. 639 */ 640 641/* 642 * The align to ATM cells is used for determining the (ATM) SAR 643 * alignment overhead at the ATM layer. (SAR = Segmentation And 644 * Reassembly). This is for example needed when scheduling packet on 645 * an ADSL connection. Note that the extra ATM-AAL overhead is _not_ 646 * included in this calculation. This overhead is added in the kernel 647 * before doing the rate table lookup, as this gives better precision 648 * (as the table will always be aligned for 48 bytes). 649 * --Hawk, d.7/11-2004. <hawk@diku.dk> 650 */ 651static unsigned int align_to_atm(unsigned int size) 652{ 653 int linksize, cells; 654 cells = size / ATM_CELL_PAYLOAD; 655 if ((size % ATM_CELL_PAYLOAD) > 0) 656 cells++; 657 658 linksize = cells * ATM_CELL_SIZE; /* Use full cell size to add ATM tax */ 659 return linksize; 660} 661 662static unsigned int adjust_size(unsigned int size, unsigned int mpu, 663 uint32_t linktype) 664{ 665 if (size < mpu) 666 size = mpu; 667 668 switch (linktype) { 669 case ARPHRD_ATM: 670 return align_to_atm(size); 671 672 case ARPHRD_ETHER: 673 default: 674 return size; 675 } 676} 677 678/** 679 * Compute a transmission time lookup table 680 * @arg tc traffic control object 681 * @arg spec Rate specification 682 * @arg dst Destination buffer of RTNL_TC_RTABLE_SIZE uint32_t[]. 683 * 684 * Computes a table of RTNL_TC_RTABLE_SIZE entries specyfing the 685 * transmission times for various packet sizes, e.g. the transmission 686 * time for a packet of size \c pktsize could be looked up: 687 * @code 688 * txtime = table[pktsize >> log2(mtu)]; 689 * @endcode 690 */ 691int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec, 692 uint32_t *dst) 693{ 694 uint32_t mtu = rtnl_tc_get_mtu(tc); 695 uint32_t linktype = rtnl_tc_get_linktype(tc); 696 uint8_t cell_log = spec->rs_cell_log; 697 unsigned int size, i; 698 699 spec->rs_mpu = rtnl_tc_get_mpu(tc); 700 spec->rs_overhead = rtnl_tc_get_overhead(tc); 701 702 if (mtu == 0) 703 mtu = 2047; 704 705 if (cell_log == UINT8_MAX) { 706 /* 707 * cell_log not specified, calculate it. It has to specify the 708 * minimum number of rshifts required to break the MTU to below 709 * RTNL_TC_RTABLE_SIZE. 710 */ 711 cell_log = 0; 712 while ((mtu >> cell_log) >= RTNL_TC_RTABLE_SIZE) 713 cell_log++; 714 } 715 716 for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) { 717 size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype); 718 dst[i] = nl_us2ticks(rtnl_tc_calc_txtime(size, spec->rs_rate)); 719 } 720 721 spec->rs_cell_align = -1; 722 spec->rs_cell_log = cell_log; 723 724 return 0; 725} 726 727/** @} */ 728 729/** 730 * @name TC implementation of cache functions 731 */ 732 733void rtnl_tc_free_data(struct nl_object *obj) 734{ 735 struct rtnl_tc *tc = TC_CAST(obj); 736 struct rtnl_tc_ops *ops; 737 738 rtnl_link_put(tc->tc_link); 739 nl_data_free(tc->tc_opts); 740 nl_data_free(tc->tc_xstats); 741 742 if (tc->tc_subdata) { 743 ops = rtnl_tc_get_ops(tc); 744 if (ops && ops->to_free_data) 745 ops->to_free_data(tc, nl_data_get(tc->tc_subdata)); 746 747 nl_data_free(tc->tc_subdata); 748 } 749} 750 751int rtnl_tc_clone(struct nl_object *dstobj, struct nl_object *srcobj) 752{ 753 struct rtnl_tc *dst = TC_CAST(dstobj); 754 struct rtnl_tc *src = TC_CAST(srcobj); 755 struct rtnl_tc_ops *ops; 756 757 if (src->tc_link) { 758 nl_object_get(OBJ_CAST(src->tc_link)); 759 dst->tc_link = src->tc_link; 760 } 761 762 if (src->tc_opts) { 763 dst->tc_opts = nl_data_clone(src->tc_opts); 764 if (!dst->tc_opts) 765 return -NLE_NOMEM; 766 } 767 768 if (src->tc_xstats) { 769 dst->tc_xstats = nl_data_clone(src->tc_xstats); 770 if (!dst->tc_xstats) 771 return -NLE_NOMEM; 772 } 773 774 if (src->tc_subdata) { 775 if (!(dst->tc_subdata = nl_data_clone(src->tc_subdata))) { 776 return -NLE_NOMEM; 777 } 778 } 779 780 ops = rtnl_tc_get_ops(src); 781 if (ops && ops->to_clone) { 782 void *a = rtnl_tc_data(dst), *b = rtnl_tc_data(src); 783 784 if (!a) 785 return 0; 786 else if (!b) 787 return -NLE_NOMEM; 788 789 return ops->to_clone(a, b); 790 } 791 792 return 0; 793} 794 795static int tc_dump(struct rtnl_tc *tc, enum nl_dump_type type, 796 struct nl_dump_params *p) 797{ 798 struct rtnl_tc_type_ops *type_ops; 799 struct rtnl_tc_ops *ops; 800 void *data = rtnl_tc_data(tc); 801 802 type_ops = tc_type_ops[tc->tc_type]; 803 if (type_ops && type_ops->tt_dump[type]) 804 type_ops->tt_dump[type](tc, p); 805 806 ops = rtnl_tc_get_ops(tc); 807 if (ops && ops->to_dump[type]) { 808 ops->to_dump[type](tc, data, p); 809 return 1; 810 } 811 812 return 0; 813} 814 815void rtnl_tc_dump_line(struct nl_object *obj, struct nl_dump_params *p) 816{ 817 struct rtnl_tc_type_ops *type_ops; 818 struct rtnl_tc *tc = TC_CAST(obj); 819 struct nl_cache *link_cache; 820 char buf[32]; 821 822 nl_new_line(p); 823 824 type_ops = tc_type_ops[tc->tc_type]; 825 if (type_ops && type_ops->tt_dump_prefix) 826 nl_dump(p, "%s ", type_ops->tt_dump_prefix); 827 828 nl_dump(p, "%s ", tc->tc_kind); 829 830 if ((link_cache = nl_cache_mngt_require_safe("route/link"))) { 831 nl_dump(p, "dev %s ", 832 rtnl_link_i2name(link_cache, tc->tc_ifindex, 833 buf, sizeof(buf))); 834 } else 835 nl_dump(p, "dev %u ", tc->tc_ifindex); 836 837 nl_dump(p, "id %s ", 838 rtnl_tc_handle2str(tc->tc_handle, buf, sizeof(buf))); 839 840 nl_dump(p, "parent %s", 841 rtnl_tc_handle2str(tc->tc_parent, buf, sizeof(buf))); 842 843 tc_dump(tc, NL_DUMP_LINE, p); 844 nl_dump(p, "\n"); 845 846 if (link_cache) 847 nl_cache_put(link_cache); 848} 849 850void rtnl_tc_dump_details(struct nl_object *obj, struct nl_dump_params *p) 851{ 852 struct rtnl_tc *tc = TC_CAST(obj); 853 854 rtnl_tc_dump_line(OBJ_CAST(tc), p); 855 856 nl_dump_line(p, " "); 857 858 if (tc->ce_mask & TCA_ATTR_MTU) 859 nl_dump(p, " mtu %u", tc->tc_mtu); 860 861 if (tc->ce_mask & TCA_ATTR_MPU) 862 nl_dump(p, " mpu %u", tc->tc_mpu); 863 864 if (tc->ce_mask & TCA_ATTR_OVERHEAD) 865 nl_dump(p, " overhead %u", tc->tc_overhead); 866 867 if (!tc_dump(tc, NL_DUMP_DETAILS, p)) 868 nl_dump(p, "no options"); 869 nl_dump(p, "\n"); 870} 871 872void rtnl_tc_dump_stats(struct nl_object *obj, struct nl_dump_params *p) 873{ 874 struct rtnl_tc *tc = TC_CAST(obj); 875 char *unit, fmt[64]; 876 float res; 877 878 rtnl_tc_dump_details(OBJ_CAST(tc), p); 879 880 strcpy(fmt, " %7.2f %s %10u %10u %10u %10u %10u\n"); 881 882 nl_dump_line(p, 883 " Stats: bytes packets drops overlimits" \ 884 " qlen backlog\n"); 885 886 res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_BYTES], &unit); 887 if (*unit == 'B') 888 fmt[11] = '9'; 889 890 nl_dump_line(p, fmt, res, unit, 891 tc->tc_stats[RTNL_TC_PACKETS], 892 tc->tc_stats[RTNL_TC_DROPS], 893 tc->tc_stats[RTNL_TC_OVERLIMITS], 894 tc->tc_stats[RTNL_TC_QLEN], 895 tc->tc_stats[RTNL_TC_BACKLOG]); 896 897 res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_RATE_BPS], &unit); 898 899 strcpy(fmt, " %7.2f %s/s%9u pps"); 900 901 if (*unit == 'B') 902 fmt[11] = '9'; 903 904 nl_dump_line(p, fmt, res, unit, tc->tc_stats[RTNL_TC_RATE_PPS]); 905 906 tc_dump(tc, NL_DUMP_LINE, p); 907 nl_dump(p, "\n"); 908} 909 910int rtnl_tc_compare(struct nl_object *aobj, struct nl_object *bobj, 911 uint32_t attrs, int flags) 912{ 913 struct rtnl_tc *a = TC_CAST(aobj); 914 struct rtnl_tc *b = TC_CAST(bobj); 915 int diff = 0; 916 917#define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR) 918 919 diff |= TC_DIFF(HANDLE, a->tc_handle != b->tc_handle); 920 diff |= TC_DIFF(PARENT, a->tc_parent != b->tc_parent); 921 diff |= TC_DIFF(IFINDEX, a->tc_ifindex != b->tc_ifindex); 922 diff |= TC_DIFF(KIND, strcmp(a->tc_kind, b->tc_kind)); 923 924#undef TC_DIFF 925 926 return diff; 927} 928 929/** @} */ 930 931/** 932 * @name Modules API 933 */ 934 935struct rtnl_tc_ops *rtnl_tc_lookup_ops(enum rtnl_tc_type type, const char *kind) 936{ 937 struct rtnl_tc_ops *ops; 938 939 nl_list_for_each_entry(ops, &tc_ops_list[type], to_list) 940 if (!strcmp(kind, ops->to_kind)) 941 return ops; 942 943 return NULL; 944} 945 946struct rtnl_tc_ops *rtnl_tc_get_ops(struct rtnl_tc *tc) 947{ 948 if (!tc->tc_ops) 949 tc->tc_ops = rtnl_tc_lookup_ops(tc->tc_type, tc->tc_kind); 950 951 return tc->tc_ops; 952} 953 954/** 955 * Register a traffic control module 956 * @arg ops traffic control module operations 957 */ 958int rtnl_tc_register(struct rtnl_tc_ops *ops) 959{ 960 static int init = 0; 961 962 /* 963 * Initialiation hack, make sure list is initialized when 964 * the first tc module registers. Putting this in a 965 * separate __init would required correct ordering of init 966 * functions 967 */ 968 if (!init) { 969 int i; 970 971 for (i = 0; i < __RTNL_TC_TYPE_MAX; i++) 972 nl_init_list_head(&tc_ops_list[i]); 973 974 init = 1; 975 } 976 977 if (!ops->to_kind || ops->to_type > RTNL_TC_TYPE_MAX) 978 BUG(); 979 980 if (rtnl_tc_lookup_ops(ops->to_type, ops->to_kind)) 981 return -NLE_EXIST; 982 983 nl_list_add_tail(&ops->to_list, &tc_ops_list[ops->to_type]); 984 985 return 0; 986} 987 988/** 989 * Unregister a traffic control module 990 * @arg ops traffic control module operations 991 */ 992void rtnl_tc_unregister(struct rtnl_tc_ops *ops) 993{ 994 nl_list_del(&ops->to_list); 995} 996 997/** 998 * Return pointer to private data of traffic control object 999 * @arg tc traffic control object 1000 * 1001 * Allocates the private traffic control object data section 1002 * as necessary and returns it. 1003 * 1004 * @return Pointer to private tc data or NULL if allocation failed. 1005 */ 1006void *rtnl_tc_data(struct rtnl_tc *tc) 1007{ 1008 if (!tc->tc_subdata) { 1009 size_t size; 1010 1011 if (!tc->tc_ops) { 1012 if (!tc->tc_kind) 1013 BUG(); 1014 1015 if (!rtnl_tc_get_ops(tc)) 1016 return NULL; 1017 } 1018 1019 if (!(size = tc->tc_ops->to_size)) 1020 BUG(); 1021 1022 if (!(tc->tc_subdata = nl_data_alloc(NULL, size))) 1023 return NULL; 1024 } 1025 1026 return nl_data_get(tc->tc_subdata); 1027} 1028 1029/** 1030 * Check traffic control object type and return private data section 1031 * @arg tc traffic control object 1032 * @arg ops expected traffic control object operations 1033 * 1034 * Checks whether the traffic control object matches the type 1035 * specified with the traffic control object operations. If the 1036 * type matches, the private tc object data is returned. If type 1037 * mismatches, APPBUG() will print a application bug warning. 1038 * 1039 * @see rtnl_tc_data() 1040 * 1041 * @return Pointer to private tc data or NULL if type mismatches. 1042 */ 1043void *rtnl_tc_data_check(struct rtnl_tc *tc, struct rtnl_tc_ops *ops) 1044{ 1045 if (tc->tc_ops != ops) { 1046 char buf[64]; 1047 1048 snprintf(buf, sizeof(buf), 1049 "tc object %p used in %s context but is of type %s", 1050 tc, ops->to_kind, tc->tc_ops->to_kind); 1051 APPBUG(buf); 1052 1053 return NULL; 1054 } 1055 1056 return rtnl_tc_data(tc); 1057} 1058 1059struct nl_af_group tc_groups[] = { 1060 { AF_UNSPEC, RTNLGRP_TC }, 1061 { END_OF_GROUP_LIST }, 1062}; 1063 1064 1065void rtnl_tc_type_register(struct rtnl_tc_type_ops *ops) 1066{ 1067 if (ops->tt_type > RTNL_TC_TYPE_MAX) 1068 BUG(); 1069 1070 tc_type_ops[ops->tt_type] = ops; 1071} 1072 1073void rtnl_tc_type_unregister(struct rtnl_tc_type_ops *ops) 1074{ 1075 if (ops->tt_type > RTNL_TC_TYPE_MAX) 1076 BUG(); 1077 1078 tc_type_ops[ops->tt_type] = NULL; 1079} 1080 1081/** @} */ 1082 1083/** @} */ 1084