libnl
3.2.3
|
00001 /* 00002 * lib/route/tc.c Traffic Control 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup rtnl 00014 * @defgroup tc Traffic Control 00015 * @{ 00016 */ 00017 00018 #include <netlink-local.h> 00019 #include <netlink-tc.h> 00020 #include <netlink/netlink.h> 00021 #include <netlink/utils.h> 00022 #include <netlink/route/rtnl.h> 00023 #include <netlink/route/link.h> 00024 #include <netlink/route/tc.h> 00025 #include <netlink/route/tc-api.h> 00026 00027 /** @cond SKIP */ 00028 00029 static struct nl_list_head tc_ops_list[__RTNL_TC_TYPE_MAX]; 00030 static struct rtnl_tc_type_ops *tc_type_ops[__RTNL_TC_TYPE_MAX]; 00031 00032 static struct nla_policy tc_policy[TCA_MAX+1] = { 00033 [TCA_KIND] = { .type = NLA_STRING, 00034 .maxlen = TCKINDSIZ }, 00035 [TCA_STATS] = { .minlen = sizeof(struct tc_stats) }, 00036 [TCA_STATS2] = { .type = NLA_NESTED }, 00037 }; 00038 00039 int tca_parse(struct nlattr **tb, int maxattr, struct rtnl_tc *g, 00040 struct nla_policy *policy) 00041 { 00042 00043 if (g->ce_mask & TCA_ATTR_OPTS) 00044 return nla_parse(tb, maxattr, 00045 (struct nlattr *) g->tc_opts->d_data, 00046 g->tc_opts->d_size, policy); 00047 else { 00048 /* Ugly but tb[] must be in a defined state even if no 00049 * attributes can be found. */ 00050 memset(tb, 0, sizeof(struct nlattr *) * (maxattr + 1)); 00051 return 0; 00052 } 00053 } 00054 00055 static struct nla_policy tc_stats2_policy[TCA_STATS_MAX+1] = { 00056 [TCA_STATS_BASIC] = { .minlen = sizeof(struct gnet_stats_basic) }, 00057 [TCA_STATS_RATE_EST] = { .minlen = sizeof(struct gnet_stats_rate_est) }, 00058 [TCA_STATS_QUEUE] = { .minlen = sizeof(struct gnet_stats_queue) }, 00059 }; 00060 00061 int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc) 00062 { 00063 struct nl_cache *link_cache; 00064 struct rtnl_tc_ops *ops; 00065 struct nlattr *tb[TCA_MAX + 1]; 00066 char kind[TCKINDSIZ]; 00067 struct tcmsg *tm; 00068 int err; 00069 00070 tc->ce_msgtype = n->nlmsg_type; 00071 00072 err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy); 00073 if (err < 0) 00074 return err; 00075 00076 if (tb[TCA_KIND] == NULL) 00077 return -NLE_MISSING_ATTR; 00078 00079 nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind)); 00080 rtnl_tc_set_kind(tc, kind); 00081 00082 tm = nlmsg_data(n); 00083 tc->tc_family = tm->tcm_family; 00084 tc->tc_ifindex = tm->tcm_ifindex; 00085 tc->tc_handle = tm->tcm_handle; 00086 tc->tc_parent = tm->tcm_parent; 00087 tc->tc_info = tm->tcm_info; 00088 00089 tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE| 00090 TCA_ATTR_PARENT | TCA_ATTR_INFO); 00091 00092 if (tb[TCA_OPTIONS]) { 00093 tc->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]); 00094 if (!tc->tc_opts) 00095 return -NLE_NOMEM; 00096 tc->ce_mask |= TCA_ATTR_OPTS; 00097 } 00098 00099 if (tb[TCA_STATS2]) { 00100 struct nlattr *tbs[TCA_STATS_MAX + 1]; 00101 00102 err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2], 00103 tc_stats2_policy); 00104 if (err < 0) 00105 return err; 00106 00107 if (tbs[TCA_STATS_BASIC]) { 00108 struct gnet_stats_basic *bs; 00109 00110 bs = nla_data(tbs[TCA_STATS_BASIC]); 00111 tc->tc_stats[RTNL_TC_BYTES] = bs->bytes; 00112 tc->tc_stats[RTNL_TC_PACKETS] = bs->packets; 00113 } 00114 00115 if (tbs[TCA_STATS_RATE_EST]) { 00116 struct gnet_stats_rate_est *re; 00117 00118 re = nla_data(tbs[TCA_STATS_RATE_EST]); 00119 tc->tc_stats[RTNL_TC_RATE_BPS] = re->bps; 00120 tc->tc_stats[RTNL_TC_RATE_PPS] = re->pps; 00121 } 00122 00123 if (tbs[TCA_STATS_QUEUE]) { 00124 struct gnet_stats_queue *q; 00125 00126 q = nla_data(tbs[TCA_STATS_QUEUE]); 00127 tc->tc_stats[RTNL_TC_QLEN] = q->qlen; 00128 tc->tc_stats[RTNL_TC_BACKLOG] = q->backlog; 00129 tc->tc_stats[RTNL_TC_DROPS] = q->drops; 00130 tc->tc_stats[RTNL_TC_REQUEUES] = q->requeues; 00131 tc->tc_stats[RTNL_TC_OVERLIMITS] = q->overlimits; 00132 } 00133 00134 tc->ce_mask |= TCA_ATTR_STATS; 00135 00136 if (tbs[TCA_STATS_APP]) { 00137 tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]); 00138 if (tc->tc_xstats == NULL) 00139 return -NLE_NOMEM; 00140 } else 00141 goto compat_xstats; 00142 } else { 00143 if (tb[TCA_STATS]) { 00144 struct tc_stats *st = nla_data(tb[TCA_STATS]); 00145 00146 tc->tc_stats[RTNL_TC_BYTES] = st->bytes; 00147 tc->tc_stats[RTNL_TC_PACKETS] = st->packets; 00148 tc->tc_stats[RTNL_TC_RATE_BPS] = st->bps; 00149 tc->tc_stats[RTNL_TC_RATE_PPS] = st->pps; 00150 tc->tc_stats[RTNL_TC_QLEN] = st->qlen; 00151 tc->tc_stats[RTNL_TC_BACKLOG] = st->backlog; 00152 tc->tc_stats[RTNL_TC_DROPS] = st->drops; 00153 tc->tc_stats[RTNL_TC_OVERLIMITS]= st->overlimits; 00154 00155 tc->ce_mask |= TCA_ATTR_STATS; 00156 } 00157 00158 compat_xstats: 00159 if (tb[TCA_XSTATS]) { 00160 tc->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]); 00161 if (tc->tc_xstats == NULL) 00162 return -NLE_NOMEM; 00163 tc->ce_mask |= TCA_ATTR_XSTATS; 00164 } 00165 } 00166 00167 ops = rtnl_tc_get_ops(tc); 00168 if (ops && ops->to_msg_parser) { 00169 void *data = rtnl_tc_data(tc); 00170 00171 if (!data) 00172 return -NLE_NOMEM; 00173 00174 err = ops->to_msg_parser(tc, data); 00175 if (err < 0) 00176 return err; 00177 } 00178 00179 if ((link_cache = __nl_cache_mngt_require("route/link"))) { 00180 struct rtnl_link *link; 00181 00182 if ((link = rtnl_link_get(link_cache, tc->tc_ifindex))) { 00183 rtnl_tc_set_link(tc, link); 00184 00185 /* rtnl_tc_set_link incs refcnt */ 00186 rtnl_link_put(link); 00187 } 00188 } 00189 00190 return 0; 00191 } 00192 00193 int rtnl_tc_msg_build(struct rtnl_tc *tc, int type, int flags, 00194 struct nl_msg **result) 00195 { 00196 struct nl_msg *msg; 00197 struct rtnl_tc_ops *ops; 00198 struct tcmsg tchdr = { 00199 .tcm_family = AF_UNSPEC, 00200 .tcm_ifindex = tc->tc_ifindex, 00201 .tcm_handle = tc->tc_handle, 00202 .tcm_parent = tc->tc_parent, 00203 }; 00204 int err = -NLE_MSGSIZE; 00205 00206 msg = nlmsg_alloc_simple(type, flags); 00207 if (!msg) 00208 return -NLE_NOMEM; 00209 00210 if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) 00211 goto nla_put_failure; 00212 00213 if (tc->ce_mask & TCA_ATTR_KIND) 00214 NLA_PUT_STRING(msg, TCA_KIND, tc->tc_kind); 00215 00216 ops = rtnl_tc_get_ops(tc); 00217 if (ops && ops->to_msg_fill) { 00218 struct nlattr *opts; 00219 void *data = rtnl_tc_data(tc); 00220 00221 if (!(opts = nla_nest_start(msg, TCA_OPTIONS))) 00222 goto nla_put_failure; 00223 00224 if ((err = ops->to_msg_fill(tc, data, msg)) < 0) 00225 goto nla_put_failure; 00226 00227 nla_nest_end(msg, opts); 00228 } 00229 00230 *result = msg; 00231 return 0; 00232 00233 nla_put_failure: 00234 nlmsg_free(msg); 00235 return err; 00236 } 00237 00238 void tca_set_kind(struct rtnl_tc *t, const char *kind) 00239 { 00240 strncpy(t->tc_kind, kind, sizeof(t->tc_kind) - 1); 00241 t->ce_mask |= TCA_ATTR_KIND; 00242 } 00243 00244 00245 /** @endcond */ 00246 00247 /** 00248 * @name Attributes 00249 * @{ 00250 */ 00251 00252 /** 00253 * Set interface index of traffic control object 00254 * @arg tc traffic control object 00255 * @arg ifindex interface index. 00256 * 00257 * Sets the interface index of a traffic control object. The interface 00258 * index defines the network device which this tc object is attached to. 00259 * This function will overwrite any network device assigned with previous 00260 * calls to rtnl_tc_set_ifindex() or rtnl_tc_set_link(). 00261 */ 00262 void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex) 00263 { 00264 /* Obsolete possible old link reference */ 00265 rtnl_link_put(tc->tc_link); 00266 tc->tc_link = NULL; 00267 tc->ce_mask &= ~TCA_ATTR_LINK; 00268 00269 tc->tc_ifindex = ifindex; 00270 tc->ce_mask |= TCA_ATTR_IFINDEX; 00271 } 00272 00273 /** 00274 * Return interface index of traffic control object 00275 * @arg tc traffic control object 00276 */ 00277 int rtnl_tc_get_ifindex(struct rtnl_tc *tc) 00278 { 00279 return tc->tc_ifindex; 00280 } 00281 00282 /** 00283 * Set link of traffic control object 00284 * @arg tc traffic control object 00285 * @arg link link object 00286 * 00287 * Sets the link of a traffic control object. This function serves 00288 * the same purpose as rtnl_tc_set_ifindex() but due to the continued 00289 * allowed access to the link object it gives it the possibility to 00290 * retrieve sane default values for the the MTU and the linktype. 00291 * Always prefer this function over rtnl_tc_set_ifindex() if you can 00292 * spare to have an additional link object around. 00293 */ 00294 void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link) 00295 { 00296 rtnl_link_put(tc->tc_link); 00297 00298 if (!link) 00299 return; 00300 00301 nl_object_get(OBJ_CAST(link)); 00302 tc->tc_link = link; 00303 tc->tc_ifindex = link->l_index; 00304 tc->ce_mask |= TCA_ATTR_LINK | TCA_ATTR_IFINDEX; 00305 } 00306 00307 /** 00308 * Get link of traffic control object 00309 * @arg tc traffic control object 00310 * 00311 * Returns the link of a traffic control object. The link is only 00312 * returned if it has been set before via rtnl_tc_set_link() or 00313 * if a link cache was available while parsing the tc object. This 00314 * function may still return NULL even if an ifindex is assigned to 00315 * the tc object. It will _not_ look up the link by itself. 00316 * 00317 * @note The returned link will have its reference counter incremented. 00318 * It is in the responsibility of the caller to return the 00319 * reference. 00320 * 00321 * @return link object or NULL if not set. 00322 */ 00323 struct rtnl_link *rtnl_tc_get_link(struct rtnl_tc *tc) 00324 { 00325 if (tc->tc_link) { 00326 nl_object_get(OBJ_CAST(tc->tc_link)); 00327 return tc->tc_link; 00328 } 00329 00330 return NULL; 00331 } 00332 00333 /** 00334 * Set the Maximum Transmission Unit (MTU) of traffic control object 00335 * @arg tc traffic control object 00336 * @arg mtu largest packet size expected 00337 * 00338 * Sets the MTU of a traffic control object. Not all traffic control 00339 * objects will make use of this but it helps while calculating rate 00340 * tables. This value is typically derived directly from the link 00341 * the tc object is attached to if the link has been assigned via 00342 * rtnl_tc_set_link(). It is usually not necessary to set the MTU 00343 * manually, this function is provided to allow overwriting the derived 00344 * value. 00345 */ 00346 void rtnl_tc_set_mtu(struct rtnl_tc *tc, uint32_t mtu) 00347 { 00348 tc->tc_mtu = mtu; 00349 tc->ce_mask |= TCA_ATTR_MTU; 00350 } 00351 00352 /** 00353 * Return the MTU of traffic control object 00354 * @arg tc traffic control object 00355 * 00356 * Returns the MTU of a traffic control object which has been set via: 00357 * -# User specified value set via rtnl_tc_set_mtu() 00358 * -# Dervied from link set via rtnl_tc_set_link() 00359 * -# Fall back to default: ethernet = 1500 00360 */ 00361 uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc) 00362 { 00363 if (tc->ce_mask & TCA_ATTR_MTU) 00364 return tc->tc_mtu; 00365 else if (tc->ce_mask & TCA_ATTR_LINK) 00366 return tc->tc_link->l_mtu; 00367 else 00368 return 1500; /* default to ethernet */ 00369 } 00370 00371 /** 00372 * Set the Minimum Packet Unit (MPU) of a traffic control object 00373 * @arg tc traffic control object 00374 * @arg mpu minimum packet size expected 00375 * 00376 * Sets the MPU of a traffic contorl object. It specifies the minimum 00377 * packet size to ever hit this traffic control object. Not all traffic 00378 * control objects will make use of this but it helps while calculating 00379 * rate tables. 00380 */ 00381 void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu) 00382 { 00383 tc->tc_mpu = mpu; 00384 tc->ce_mask |= TCA_ATTR_MPU; 00385 } 00386 00387 /** 00388 * Return the Minimum Packet Unit (MPU) of a traffic control object 00389 * @arg tc traffic control object 00390 * 00391 * @return The MPU previously set via rtnl_tc_set_mpu() or 0. 00392 */ 00393 uint32_t rtnl_tc_get_mpu(struct rtnl_tc *tc) 00394 { 00395 return tc->tc_mpu; 00396 } 00397 00398 /** 00399 * Set per packet overhead of a traffic control object 00400 * @arg tc traffic control object 00401 * @arg overhead overhead per packet in bytes 00402 * 00403 * Sets the per packet overhead in bytes occuring on the link not seen 00404 * by the kernel. This value can be used to correct size calculations 00405 * if the packet size on the wire does not match the packet sizes seen 00406 * in the network stack. Not all traffic control objects will make use 00407 * this but it helps while calculating accurate packet sizes in the 00408 * kernel. 00409 */ 00410 void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead) 00411 { 00412 tc->tc_overhead = overhead; 00413 tc->ce_mask |= TCA_ATTR_OVERHEAD; 00414 } 00415 00416 /** 00417 * Return per packet overhead of a traffic control object 00418 * @arg tc traffic control object 00419 * 00420 * @return The overhead previously set by rtnl_tc_set_overhead() or 0. 00421 */ 00422 uint32_t rtnl_tc_get_overhead(struct rtnl_tc *tc) 00423 { 00424 return tc->tc_overhead; 00425 } 00426 00427 /** 00428 * Set the linktype of a traffic control object 00429 * @arg tc traffic control object 00430 * @arg type type of link (e.g. ARPHRD_ATM, ARPHRD_ETHER) 00431 * 00432 * Overwrites the type of link this traffic control object is attached to. 00433 * This value is typically derived from the link this tc object is attached 00434 * if the link has been assigned via rtnl_tc_set_link(). It is usually not 00435 * necessary to set the linktype manually. This function is provided to 00436 * allow overwriting the linktype. 00437 */ 00438 void rtnl_tc_set_linktype(struct rtnl_tc *tc, uint32_t type) 00439 { 00440 tc->tc_linktype = type; 00441 tc->ce_mask |= TCA_ATTR_LINKTYPE; 00442 } 00443 00444 /** 00445 * Return the linktype of a traffic control object 00446 * @arg tc traffic control object 00447 * 00448 * Returns the linktype of the link the traffic control object is attached to: 00449 * -# User specified value via rtnl_tc_set_linktype() 00450 * -# Value derived from link set via rtnl_tc_set_link() 00451 * -# Default fall-back: ARPHRD_ETHER 00452 */ 00453 uint32_t rtnl_tc_get_linktype(struct rtnl_tc *tc) 00454 { 00455 if (tc->ce_mask & TCA_ATTR_LINKTYPE) 00456 return tc->tc_linktype; 00457 else if (tc->ce_mask & TCA_ATTR_LINK) 00458 return tc->tc_link->l_arptype; 00459 else 00460 return ARPHRD_ETHER; /* default to ethernet */ 00461 } 00462 00463 /** 00464 * Set identifier of traffic control object 00465 * @arg tc traffic control object 00466 * @arg id unique identifier 00467 */ 00468 void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id) 00469 { 00470 tc->tc_handle = id; 00471 tc->ce_mask |= TCA_ATTR_HANDLE; 00472 } 00473 00474 /** 00475 * Return identifier of a traffic control object 00476 * @arg tc traffic control object 00477 */ 00478 uint32_t rtnl_tc_get_handle(struct rtnl_tc *tc) 00479 { 00480 return tc->tc_handle; 00481 } 00482 00483 /** 00484 * Set the parent identifier of a traffic control object 00485 * @arg tc traffic control object 00486 * @arg parent identifier of parent traffif control object 00487 * 00488 */ 00489 void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent) 00490 { 00491 tc->tc_parent = parent; 00492 tc->ce_mask |= TCA_ATTR_PARENT; 00493 } 00494 00495 /** 00496 * Return parent identifier of a traffic control object 00497 * @arg tc traffic control object 00498 */ 00499 uint32_t rtnl_tc_get_parent(struct rtnl_tc *tc) 00500 { 00501 return tc->tc_parent; 00502 } 00503 00504 /** 00505 * Define the type of traffic control object 00506 * @arg tc traffic control object 00507 * @arg kind name of the tc object type 00508 * 00509 * @return 0 on success or a negative error code 00510 */ 00511 int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind) 00512 { 00513 if (tc->ce_mask & TCA_ATTR_KIND) 00514 return -NLE_EXIST; 00515 00516 strncpy(tc->tc_kind, kind, sizeof(tc->tc_kind) - 1); 00517 tc->ce_mask |= TCA_ATTR_KIND; 00518 00519 /* Force allocation of data */ 00520 rtnl_tc_data(tc); 00521 00522 return 0; 00523 } 00524 00525 /** 00526 * Return kind of traffic control object 00527 * @arg tc traffic control object 00528 * 00529 * @return Kind of traffic control object or NULL if not set. 00530 */ 00531 char *rtnl_tc_get_kind(struct rtnl_tc *tc) 00532 { 00533 if (tc->ce_mask & TCA_ATTR_KIND) 00534 return tc->tc_kind; 00535 else 00536 return NULL; 00537 } 00538 00539 /** 00540 * Return value of a statistical counter of a traffic control object 00541 * @arg tc traffic control object 00542 * @arg id identifier of statistical counter 00543 * 00544 * @return Value of requested statistic counter or 0. 00545 */ 00546 uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id) 00547 { 00548 if (id < 0 || id > RTNL_TC_STATS_MAX) 00549 return 0; 00550 00551 return tc->tc_stats[id]; 00552 } 00553 00554 /** @} */ 00555 00556 /** 00557 * @name Utilities 00558 * @{ 00559 */ 00560 00561 /** 00562 * Calculate time required to transmit buffer at a specific rate 00563 * @arg bufsize Size of buffer to be transmited in bytes. 00564 * @arg rate Transmit rate in bytes per second. 00565 * 00566 * Calculates the number of micro seconds required to transmit a 00567 * specific buffer at a specific transmit rate. 00568 * 00569 * @f[ 00570 * txtime=\frac{bufsize}{rate}10^6 00571 * @f] 00572 * 00573 * @return Required transmit time in micro seconds. 00574 */ 00575 int rtnl_tc_calc_txtime(int bufsize, int rate) 00576 { 00577 double tx_time_secs; 00578 00579 tx_time_secs = (double) bufsize / (double) rate; 00580 00581 return tx_time_secs * 1000000.; 00582 } 00583 00584 /** 00585 * Calculate buffer size able to transmit in a specific time and rate. 00586 * @arg txtime Available transmit time in micro seconds. 00587 * @arg rate Transmit rate in bytes per second. 00588 * 00589 * Calculates the size of the buffer that can be transmitted in a 00590 * specific time period at a specific transmit rate. 00591 * 00592 * @f[ 00593 * bufsize=\frac{{txtime} \times {rate}}{10^6} 00594 * @f] 00595 * 00596 * @return Size of buffer in bytes. 00597 */ 00598 int rtnl_tc_calc_bufsize(int txtime, int rate) 00599 { 00600 double bufsize; 00601 00602 bufsize = (double) txtime * (double) rate; 00603 00604 return bufsize / 1000000.; 00605 } 00606 00607 /** 00608 * Calculate the binary logarithm for a specific cell size 00609 * @arg cell_size Size of cell, must be a power of two. 00610 * @return Binary logirhtm of cell size or a negative error code. 00611 */ 00612 int rtnl_tc_calc_cell_log(int cell_size) 00613 { 00614 int i; 00615 00616 for (i = 0; i < 32; i++) 00617 if ((1 << i) == cell_size) 00618 return i; 00619 00620 return -NLE_INVAL; 00621 } 00622 00623 00624 /** @} */ 00625 00626 /** 00627 * @name Rate Tables 00628 * @{ 00629 */ 00630 00631 /* 00632 * COPYRIGHT NOTE: 00633 * align_to_atm() and adjust_size() derived/coped from iproute2 source. 00634 */ 00635 00636 /* 00637 * The align to ATM cells is used for determining the (ATM) SAR 00638 * alignment overhead at the ATM layer. (SAR = Segmentation And 00639 * Reassembly). This is for example needed when scheduling packet on 00640 * an ADSL connection. Note that the extra ATM-AAL overhead is _not_ 00641 * included in this calculation. This overhead is added in the kernel 00642 * before doing the rate table lookup, as this gives better precision 00643 * (as the table will always be aligned for 48 bytes). 00644 * --Hawk, d.7/11-2004. <hawk@diku.dk> 00645 */ 00646 static unsigned int align_to_atm(unsigned int size) 00647 { 00648 int linksize, cells; 00649 cells = size / ATM_CELL_PAYLOAD; 00650 if ((size % ATM_CELL_PAYLOAD) > 0) 00651 cells++; 00652 00653 linksize = cells * ATM_CELL_SIZE; /* Use full cell size to add ATM tax */ 00654 return linksize; 00655 } 00656 00657 static unsigned int adjust_size(unsigned int size, unsigned int mpu, 00658 uint32_t linktype) 00659 { 00660 if (size < mpu) 00661 size = mpu; 00662 00663 switch (linktype) { 00664 case ARPHRD_ATM: 00665 return align_to_atm(size); 00666 00667 case ARPHRD_ETHER: 00668 default: 00669 return size; 00670 } 00671 } 00672 00673 /** 00674 * Compute a transmission time lookup table 00675 * @arg tc traffic control object 00676 * @arg spec Rate specification 00677 * @arg dst Destination buffer of RTNL_TC_RTABLE_SIZE uint32_t[]. 00678 * 00679 * Computes a table of RTNL_TC_RTABLE_SIZE entries specyfing the 00680 * transmission times for various packet sizes, e.g. the transmission 00681 * time for a packet of size \c pktsize could be looked up: 00682 * @code 00683 * txtime = table[pktsize >> log2(mtu)]; 00684 * @endcode 00685 */ 00686 int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec, 00687 uint32_t *dst) 00688 { 00689 uint32_t mtu = rtnl_tc_get_mtu(tc); 00690 uint32_t linktype = rtnl_tc_get_linktype(tc); 00691 uint8_t cell_log = spec->rs_cell_log; 00692 unsigned int size, i; 00693 00694 spec->rs_mpu = rtnl_tc_get_mpu(tc); 00695 spec->rs_overhead = rtnl_tc_get_overhead(tc); 00696 00697 if (mtu == 0) 00698 mtu = 2047; 00699 00700 if (cell_log == UINT8_MAX) { 00701 /* 00702 * cell_log not specified, calculate it. It has to specify the 00703 * minimum number of rshifts required to break the MTU to below 00704 * RTNL_TC_RTABLE_SIZE. 00705 */ 00706 cell_log = 0; 00707 while ((mtu >> cell_log) >= RTNL_TC_RTABLE_SIZE) 00708 cell_log++; 00709 } 00710 00711 for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) { 00712 size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype); 00713 dst[i] = rtnl_tc_calc_txtime(size, spec->rs_rate); 00714 } 00715 00716 spec->rs_cell_align = -1; 00717 spec->rs_cell_log = cell_log; 00718 00719 return 0; 00720 } 00721 00722 /** @} */ 00723 00724 /** 00725 * @name TC implementation of cache functions 00726 */ 00727 00728 void rtnl_tc_free_data(struct nl_object *obj) 00729 { 00730 struct rtnl_tc *tc = TC_CAST(obj); 00731 struct rtnl_tc_ops *ops; 00732 00733 rtnl_link_put(tc->tc_link); 00734 nl_data_free(tc->tc_opts); 00735 nl_data_free(tc->tc_xstats); 00736 00737 if (tc->tc_subdata) { 00738 ops = rtnl_tc_get_ops(tc); 00739 if (ops && ops->to_free_data) 00740 ops->to_free_data(tc, nl_data_get(tc->tc_subdata)); 00741 00742 nl_data_free(tc->tc_subdata); 00743 } 00744 } 00745 00746 int rtnl_tc_clone(struct nl_object *dstobj, struct nl_object *srcobj) 00747 { 00748 struct rtnl_tc *dst = TC_CAST(dstobj); 00749 struct rtnl_tc *src = TC_CAST(srcobj); 00750 struct rtnl_tc_ops *ops; 00751 00752 if (src->tc_link) { 00753 nl_object_get(OBJ_CAST(src->tc_link)); 00754 dst->tc_link = src->tc_link; 00755 } 00756 00757 if (src->tc_opts) { 00758 dst->tc_opts = nl_data_clone(src->tc_opts); 00759 if (!dst->tc_opts) 00760 return -NLE_NOMEM; 00761 } 00762 00763 if (src->tc_xstats) { 00764 dst->tc_xstats = nl_data_clone(src->tc_xstats); 00765 if (!dst->tc_xstats) 00766 return -NLE_NOMEM; 00767 } 00768 00769 if (src->tc_subdata) { 00770 if (!(dst->tc_subdata = nl_data_clone(src->tc_subdata))) { 00771 return -NLE_NOMEM; 00772 } 00773 } 00774 00775 ops = rtnl_tc_get_ops(src); 00776 if (ops && ops->to_clone) { 00777 void *a = rtnl_tc_data(dst), *b = rtnl_tc_data(src); 00778 00779 if (!a) 00780 return 0; 00781 else if (!b) 00782 return -NLE_NOMEM; 00783 00784 return ops->to_clone(a, b); 00785 } 00786 00787 return 0; 00788 } 00789 00790 static int tc_dump(struct rtnl_tc *tc, enum nl_dump_type type, 00791 struct nl_dump_params *p) 00792 { 00793 struct rtnl_tc_type_ops *type_ops; 00794 struct rtnl_tc_ops *ops; 00795 void *data = rtnl_tc_data(tc); 00796 00797 type_ops = tc_type_ops[tc->tc_type]; 00798 if (type_ops && type_ops->tt_dump[type]) 00799 type_ops->tt_dump[type](tc, p); 00800 00801 ops = rtnl_tc_get_ops(tc); 00802 if (ops && ops->to_dump[type]) { 00803 ops->to_dump[type](tc, data, p); 00804 return 1; 00805 } 00806 00807 return 0; 00808 } 00809 00810 void rtnl_tc_dump_line(struct nl_object *obj, struct nl_dump_params *p) 00811 { 00812 struct rtnl_tc_type_ops *type_ops; 00813 struct rtnl_tc *tc = TC_CAST(obj); 00814 struct nl_cache *link_cache; 00815 char buf[32]; 00816 00817 nl_new_line(p); 00818 00819 type_ops = tc_type_ops[tc->tc_type]; 00820 if (type_ops && type_ops->tt_dump_prefix) 00821 nl_dump(p, "%s ", type_ops->tt_dump_prefix); 00822 00823 nl_dump(p, "%s ", tc->tc_kind); 00824 00825 if ((link_cache = nl_cache_mngt_require("route/link"))) { 00826 nl_dump(p, "dev %s ", 00827 rtnl_link_i2name(link_cache, tc->tc_ifindex, 00828 buf, sizeof(buf))); 00829 } else 00830 nl_dump(p, "dev %u ", tc->tc_ifindex); 00831 00832 nl_dump(p, "id %s ", 00833 rtnl_tc_handle2str(tc->tc_handle, buf, sizeof(buf))); 00834 00835 nl_dump(p, "parent %s", 00836 rtnl_tc_handle2str(tc->tc_parent, buf, sizeof(buf))); 00837 00838 tc_dump(tc, NL_DUMP_LINE, p); 00839 nl_dump(p, "\n"); 00840 } 00841 00842 void rtnl_tc_dump_details(struct nl_object *obj, struct nl_dump_params *p) 00843 { 00844 struct rtnl_tc *tc = TC_CAST(obj); 00845 00846 rtnl_tc_dump_line(OBJ_CAST(tc), p); 00847 00848 nl_dump_line(p, " "); 00849 00850 if (tc->ce_mask & TCA_ATTR_MTU) 00851 nl_dump(p, " mtu %u", tc->tc_mtu); 00852 00853 if (tc->ce_mask & TCA_ATTR_MPU) 00854 nl_dump(p, " mpu %u", tc->tc_mpu); 00855 00856 if (tc->ce_mask & TCA_ATTR_OVERHEAD) 00857 nl_dump(p, " overhead %u", tc->tc_overhead); 00858 00859 if (!tc_dump(tc, NL_DUMP_DETAILS, p)) 00860 nl_dump(p, "no options"); 00861 nl_dump(p, "\n"); 00862 } 00863 00864 void rtnl_tc_dump_stats(struct nl_object *obj, struct nl_dump_params *p) 00865 { 00866 struct rtnl_tc *tc = TC_CAST(obj); 00867 char *unit, fmt[64]; 00868 float res; 00869 00870 rtnl_tc_dump_details(OBJ_CAST(tc), p); 00871 00872 strcpy(fmt, " %7.2f %s %10u %10u %10u %10u %10u\n"); 00873 00874 nl_dump_line(p, 00875 " Stats: bytes packets drops overlimits" \ 00876 " qlen backlog\n"); 00877 00878 res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_BYTES], &unit); 00879 if (*unit == 'B') 00880 fmt[11] = '9'; 00881 00882 nl_dump_line(p, fmt, res, unit, 00883 tc->tc_stats[RTNL_TC_PACKETS], 00884 tc->tc_stats[RTNL_TC_DROPS], 00885 tc->tc_stats[RTNL_TC_OVERLIMITS], 00886 tc->tc_stats[RTNL_TC_QLEN], 00887 tc->tc_stats[RTNL_TC_BACKLOG]); 00888 00889 res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_RATE_BPS], &unit); 00890 00891 strcpy(fmt, " %7.2f %s/s%9u pps"); 00892 00893 if (*unit == 'B') 00894 fmt[11] = '9'; 00895 00896 nl_dump_line(p, fmt, res, unit, tc->tc_stats[RTNL_TC_RATE_PPS]); 00897 00898 tc_dump(tc, NL_DUMP_LINE, p); 00899 nl_dump(p, "\n"); 00900 } 00901 00902 int rtnl_tc_compare(struct nl_object *aobj, struct nl_object *bobj, 00903 uint32_t attrs, int flags) 00904 { 00905 struct rtnl_tc *a = TC_CAST(aobj); 00906 struct rtnl_tc *b = TC_CAST(bobj); 00907 int diff = 0; 00908 00909 #define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR) 00910 00911 diff |= TC_DIFF(HANDLE, a->tc_handle != b->tc_handle); 00912 diff |= TC_DIFF(PARENT, a->tc_parent != b->tc_parent); 00913 diff |= TC_DIFF(IFINDEX, a->tc_ifindex != b->tc_ifindex); 00914 diff |= TC_DIFF(KIND, strcmp(a->tc_kind, b->tc_kind)); 00915 00916 #undef TC_DIFF 00917 00918 return diff; 00919 } 00920 00921 /** @} */ 00922 00923 /** 00924 * @name Modules API 00925 */ 00926 00927 struct rtnl_tc_ops *rtnl_tc_lookup_ops(enum rtnl_tc_type type, const char *kind) 00928 { 00929 struct rtnl_tc_ops *ops; 00930 00931 nl_list_for_each_entry(ops, &tc_ops_list[type], to_list) 00932 if (!strcmp(kind, ops->to_kind)) 00933 return ops; 00934 00935 return NULL; 00936 } 00937 00938 struct rtnl_tc_ops *rtnl_tc_get_ops(struct rtnl_tc *tc) 00939 { 00940 if (!tc->tc_ops) 00941 tc->tc_ops = rtnl_tc_lookup_ops(tc->tc_type, tc->tc_kind); 00942 00943 return tc->tc_ops; 00944 } 00945 00946 /** 00947 * Register a traffic control module 00948 * @arg ops traffic control module operations 00949 */ 00950 int rtnl_tc_register(struct rtnl_tc_ops *ops) 00951 { 00952 static int init = 0; 00953 00954 /* 00955 * Initialiation hack, make sure list is initialized when 00956 * the first tc module registers. Putting this in a 00957 * separate __init would required correct ordering of init 00958 * functions 00959 */ 00960 if (!init) { 00961 int i; 00962 00963 for (i = 0; i < __RTNL_TC_TYPE_MAX; i++) 00964 nl_init_list_head(&tc_ops_list[i]); 00965 00966 init = 1; 00967 } 00968 00969 if (!ops->to_kind || ops->to_type > RTNL_TC_TYPE_MAX) 00970 BUG(); 00971 00972 if (rtnl_tc_lookup_ops(ops->to_type, ops->to_kind)) 00973 return -NLE_EXIST; 00974 00975 nl_list_add_tail(&ops->to_list, &tc_ops_list[ops->to_type]); 00976 00977 return 0; 00978 } 00979 00980 /** 00981 * Unregister a traffic control module 00982 * @arg ops traffic control module operations 00983 */ 00984 void rtnl_tc_unregister(struct rtnl_tc_ops *ops) 00985 { 00986 nl_list_del(&ops->to_list); 00987 } 00988 00989 /** 00990 * Return pointer to private data of traffic control object 00991 * @arg tc traffic control object 00992 * 00993 * Allocates the private traffic control object data section 00994 * as necessary and returns it. 00995 * 00996 * @return Pointer to private tc data or NULL if allocation failed. 00997 */ 00998 void *rtnl_tc_data(struct rtnl_tc *tc) 00999 { 01000 if (!tc->tc_subdata) { 01001 size_t size; 01002 01003 if (!tc->tc_ops) { 01004 if (!tc->tc_kind) 01005 BUG(); 01006 01007 if (!rtnl_tc_get_ops(tc)) 01008 return NULL; 01009 } 01010 01011 if (!(size = tc->tc_ops->to_size)) 01012 BUG(); 01013 01014 if (!(tc->tc_subdata = nl_data_alloc(NULL, size))) 01015 return NULL; 01016 } 01017 01018 return nl_data_get(tc->tc_subdata); 01019 } 01020 01021 /** 01022 * Check traffic control object type and return private data section 01023 * @arg tc traffic control object 01024 * @arg ops expected traffic control object operations 01025 * 01026 * Checks whether the traffic control object matches the type 01027 * specified with the traffic control object operations. If the 01028 * type matches, the private tc object data is returned. If type 01029 * mismatches, APPBUG() will print a application bug warning. 01030 * 01031 * @see rtnl_tc_data() 01032 * 01033 * @return Pointer to private tc data or NULL if type mismatches. 01034 */ 01035 void *rtnl_tc_data_check(struct rtnl_tc *tc, struct rtnl_tc_ops *ops) 01036 { 01037 if (tc->tc_ops != ops) { 01038 char buf[64]; 01039 01040 snprintf(buf, sizeof(buf), 01041 "tc object %p used in %s context but is of type %s", 01042 tc, ops->to_kind, tc->tc_ops->to_kind); 01043 APPBUG(buf); 01044 01045 return NULL; 01046 } 01047 01048 return rtnl_tc_data(tc); 01049 } 01050 01051 void rtnl_tc_type_register(struct rtnl_tc_type_ops *ops) 01052 { 01053 if (ops->tt_type > RTNL_TC_TYPE_MAX) 01054 BUG(); 01055 01056 tc_type_ops[ops->tt_type] = ops; 01057 } 01058 01059 void rtnl_tc_type_unregister(struct rtnl_tc_type_ops *ops) 01060 { 01061 if (ops->tt_type > RTNL_TC_TYPE_MAX) 01062 BUG(); 01063 01064 tc_type_ops[ops->tt_type] = NULL; 01065 } 01066 01067 /** @} */ 01068 01069 /** @} */