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