libnl  3.2.3
/build/buildd/libnl3-3.2.3/lib/route/tc.c
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 /** @} */