/build/buildd/libnl-1.0~pre6/lib/route/sch/htb.c

00001 /*
00002  * lib/route/sch/htb.c  HTB Qdisc
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-2006 Thomas Graf <tgraf@suug.ch>
00010  * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
00011  * Copyright (c) 2005-2006 Siemens AG Oesterreich
00012  */
00013 
00014 /**
00015  * @ingroup qdisc
00016  * @ingroup class
00017  * @defgroup htb Hierachical Token Bucket (HTB)
00018  * @{
00019  */
00020 
00021 #include <netlink-local.h>
00022 #include <netlink-tc.h>
00023 #include <netlink/netlink.h>
00024 #include <netlink/cache.h>
00025 #include <netlink/utils.h>
00026 #include <netlink/route/tc.h>
00027 #include <netlink/route/qdisc.h>
00028 #include <netlink/route/qdisc-modules.h>
00029 #include <netlink/route/class.h>
00030 #include <netlink/route/class-modules.h>
00031 #include <netlink/route/link.h>
00032 #include <netlink/route/sch/htb.h>
00033 
00034 /** @cond SKIP */
00035 #define SCH_HTB_HAS_RATE2QUANTUM        0x01
00036 #define SCH_HTB_HAS_DEFCLS              0x02
00037 
00038 #define SCH_HTB_HAS_PRIO                0x01
00039 #define SCH_HTB_HAS_MTU                 0x02
00040 #define SCH_HTB_HAS_RATE                0x04
00041 #define SCH_HTB_HAS_CEIL                0x08
00042 #define SCH_HTB_HAS_RBUFFER             0x10
00043 #define SCH_HTB_HAS_CBUFFER             0x20
00044 /** @endcond */
00045 
00046 static inline struct rtnl_htb_qdisc *htb_qdisc(struct rtnl_qdisc *qdisc)
00047 {
00048         if (qdisc->q_subdata == NULL)
00049                 qdisc->q_subdata = calloc(1, sizeof(struct rtnl_htb_qdisc));
00050 
00051         return (struct rtnl_htb_qdisc *) qdisc->q_subdata;
00052 }
00053 
00054 static struct nla_policy htb_policy[TCA_HTB_MAX+1] = {
00055         [TCA_HTB_INIT]  = { .minlen = sizeof(struct tc_htb_glob) },
00056         [TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) },
00057 };
00058 
00059 static int htb_qdisc_msg_parser(struct rtnl_qdisc *qdisc)
00060 {
00061         int err;
00062         struct nlattr *tb[TCA_HTB_MAX + 1];
00063         struct rtnl_htb_qdisc *d;
00064 
00065         err = tca_parse(tb, TCA_HTB_MAX, (struct rtnl_tca *) qdisc, htb_policy);
00066         if (err < 0)
00067                 return err;
00068         
00069         d = htb_qdisc(qdisc);
00070 
00071         if (tb[TCA_HTB_INIT]) {
00072                 struct tc_htb_glob opts;
00073 
00074                 nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts));
00075                 d->qh_rate2quantum = opts.rate2quantum;
00076                 d->qh_defcls = opts.defcls;
00077 
00078                 d->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS);
00079         }
00080 
00081         return 0;
00082 }
00083 
00084 static void htb_qdisc_free_data(struct rtnl_qdisc *qdisc)
00085 {
00086         free(qdisc->q_subdata);
00087 }
00088 
00089 static inline struct rtnl_htb_class *htb_class(struct rtnl_class *class)
00090 {
00091         if (class->c_subdata == NULL)
00092                 class->c_subdata = calloc(1, sizeof(struct rtnl_htb_class));
00093 
00094         return (struct rtnl_htb_class *) class->c_subdata;
00095 }
00096 
00097 static int htb_class_msg_parser(struct rtnl_class *class)
00098 {
00099         int err;
00100         struct nlattr *tb[TCA_HTB_MAX + 1];
00101         struct rtnl_htb_class *d;
00102 
00103         err = tca_parse(tb, TCA_HTB_MAX, (struct rtnl_tca *) class, htb_policy);
00104         if (err < 0)
00105                 return err;
00106         
00107         d = htb_class(class);
00108 
00109         if (tb[TCA_HTB_PARMS]) {
00110                 struct tc_htb_opt opts;
00111 
00112                 nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts));
00113                 d->ch_prio = opts.prio;
00114                 rtnl_copy_ratespec(&d->ch_rate, &opts.rate);
00115                 rtnl_copy_ratespec(&d->ch_ceil, &opts.ceil);
00116                 d->ch_rbuffer = opts.buffer;
00117                 d->ch_cbuffer = opts.cbuffer;
00118 
00119                 d->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE |
00120                         SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER |
00121                         SCH_HTB_HAS_CBUFFER);
00122         }
00123 
00124         return 0;
00125 }
00126 
00127 static void htb_class_free_data(struct rtnl_class *class)
00128 {
00129         free(class->c_subdata);
00130 }
00131 
00132 static int htb_qdisc_dump_brief(struct rtnl_qdisc *qdisc,
00133                                 struct nl_dump_params *p, int line)
00134 {
00135         struct rtnl_htb_qdisc *d = (struct rtnl_htb_qdisc *) qdisc->q_subdata;
00136 
00137         if (d == NULL)
00138                 goto ignore;
00139 
00140         if (d->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
00141                 dp_dump(p, " r2q %u", d->qh_rate2quantum);
00142 
00143         if (d->qh_mask & SCH_HTB_HAS_DEFCLS) {
00144                 char buf[32];
00145                 dp_dump(p, " default %s",
00146                         rtnl_tc_handle2str(d->qh_defcls, buf, sizeof(buf)));
00147         }
00148 
00149 ignore:
00150         return line;
00151 }
00152 
00153 static int htb_class_dump_brief(struct rtnl_class *class,
00154                                 struct nl_dump_params *p, int line)
00155 {
00156         struct rtnl_htb_class *d = (struct rtnl_htb_class *) class->c_subdata;
00157 
00158         if (d == NULL)
00159                 goto ignore;
00160 
00161         if (d->ch_mask & SCH_HTB_HAS_RATE) {
00162                 double r, rbit;
00163                 char *ru, *rubit;
00164 
00165                 r = nl_cancel_down_bytes(d->ch_rate.rs_rate, &ru);
00166                 rbit = nl_cancel_down_bits(d->ch_rate.rs_rate*8, &rubit);
00167 
00168                 dp_dump(p, " rate %.2f%s/s (%.0f%s) log %u",
00169                         r, ru, rbit, rubit, 1<<d->ch_rate.rs_cell_log);
00170         }
00171 
00172 ignore:
00173         return line;
00174 }
00175 
00176 static int htb_class_dump_full(struct rtnl_class *class,
00177                                struct nl_dump_params *p, int line)
00178 {
00179         struct rtnl_htb_class *d = (struct rtnl_htb_class *) class->c_subdata;
00180 
00181         if (d == NULL)
00182                 goto ignore;
00183 
00184         /* line 1 */
00185         if (d->ch_mask & SCH_HTB_HAS_CEIL) {
00186                 double r, rbit;
00187                 char *ru, *rubit;
00188 
00189                 r = nl_cancel_down_bytes(d->ch_ceil.rs_rate, &ru);
00190                 rbit = nl_cancel_down_bits(d->ch_ceil.rs_rate*8, &rubit);
00191 
00192                 dp_dump(p, "    ceil %.2f%s/s (%.0f%s) log %u",
00193                         r, ru, rbit, rubit, 1<<d->ch_ceil.rs_cell_log);
00194         }
00195 
00196         if (d->ch_mask & SCH_HTB_HAS_PRIO)
00197                 dp_dump(p, " prio %u", d->ch_prio);
00198         if (d->ch_mask & SCH_HTB_HAS_RBUFFER)
00199                 dp_dump(p, " rbuffer %u", d->ch_rbuffer);
00200         if (d->ch_mask & SCH_HTB_HAS_CBUFFER)
00201                 dp_dump(p, " cbuffer %u", d->ch_cbuffer);
00202 
00203 ignore:
00204         return line;
00205 }
00206 
00207 static struct nl_msg *htb_qdisc_get_opts(struct rtnl_qdisc *qdisc)
00208 {
00209         struct rtnl_htb_qdisc *d = (struct rtnl_htb_qdisc *) qdisc->q_subdata;
00210         struct tc_htb_glob opts;
00211         struct nl_msg *msg;
00212 
00213         if (d == NULL)
00214                 return NULL;
00215 
00216         msg = nlmsg_build(NULL);
00217         if (msg == NULL)
00218                 return NULL;
00219 
00220         memset(&opts, 0, sizeof(opts));
00221         opts.version = TC_HTB_PROTOVER;
00222 
00223         if (d->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
00224                 opts.rate2quantum = d->qh_rate2quantum;
00225         if (d->qh_mask & SCH_HTB_HAS_DEFCLS)
00226                 opts.defcls = d->qh_defcls;
00227 
00228         nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts);
00229 
00230         return msg;
00231 }
00232 
00233 static inline uint32_t compute_burst(uint32_t rate, uint32_t mtu)
00234 {
00235         return rtnl_tc_calc_txtime(rate / nl_get_hz() + mtu, rate);
00236 }
00237 
00238 static uint8_t compute_cell(uint32_t rate, uint32_t mtu)
00239 {
00240         uint8_t cell_log = 0;
00241         while (mtu > 255) {
00242                 mtu >>= 1;
00243                 cell_log++;
00244         }
00245 
00246         return cell_log;
00247 }
00248 
00249 static struct nl_msg *htb_class_get_opts(struct rtnl_class *class)
00250 {
00251         struct rtnl_htb_class *d = (struct rtnl_htb_class *) class->c_subdata;
00252         uint32_t rtable[256], ctable[256];
00253         struct tc_htb_opt opts;
00254         struct nl_msg *msg;
00255         
00256 
00257         if (d == NULL)
00258                 return NULL;
00259 
00260         msg = nlmsg_build(NULL);
00261         memset(&opts, 0, sizeof(opts));
00262 
00263         /* if not set, zero (0) is used as priority */
00264         if (d->ch_mask & SCH_HTB_HAS_PRIO)
00265                 opts.prio = d->ch_prio;
00266 
00267         if (!(d->ch_mask & SCH_HTB_HAS_RATE))
00268                 BUG();
00269 
00270         rtnl_rcopy_ratespec(&opts.rate, &d->ch_rate);
00271         /* if cell_log not set, compute default value */
00272         if (opts.rate.cell_log == UINT8_MAX)
00273         {
00274                 if(!(d->ch_mask & SCH_HTB_HAS_MTU))
00275                         BUG();
00276                 opts.rate.cell_log = compute_cell(opts.rate.rate, d->ch_mtu);
00277         }
00278 
00279         /* if not set, configured rate is used as ceil, which implies no borrowing */
00280         if (d->ch_mask & SCH_HTB_HAS_CEIL)
00281                 rtnl_rcopy_ratespec(&opts.ceil, &d->ch_ceil);
00282         else
00283                 memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec));
00284         /* if cell_log not set, compute default value */
00285         if (opts.ceil.cell_log == UINT8_MAX)
00286         {
00287                 if(!(d->ch_mask & SCH_HTB_HAS_MTU))
00288                         BUG();
00289                 opts.ceil.cell_log = compute_cell(opts.ceil.rate, d->ch_mtu);
00290         }
00291 
00292         if (d->ch_mask & SCH_HTB_HAS_RBUFFER)
00293                 opts.buffer = d->ch_rbuffer;
00294         else
00295         {
00296                 if(!(d->ch_mask & SCH_HTB_HAS_MTU))
00297                         BUG();
00298                 opts.buffer = compute_burst(opts.rate.rate, d->ch_mtu);
00299         }
00300 
00301         if (d->ch_mask & SCH_HTB_HAS_CBUFFER)
00302                 opts.cbuffer = d->ch_cbuffer;
00303         else
00304         {
00305                 if(!(d->ch_mask & SCH_HTB_HAS_MTU))
00306                         BUG();
00307                 opts.cbuffer = compute_burst(opts.ceil.rate, d->ch_mtu);
00308         }
00309 
00310         nla_put(msg, TCA_HTB_PARMS, sizeof(opts), &opts);
00311         rtnl_tc_build_rate_table(rtable, opts.rate.mpu & 0xff,
00312                                  opts.rate.mpu >> 8, 1 << opts.rate.cell_log,
00313                                  opts.rate.rate);
00314         nla_put(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable);
00315         rtnl_tc_build_rate_table(ctable, opts.ceil.mpu & 0xff,
00316                                  opts.ceil.mpu >> 8, 1 << opts.ceil.cell_log,
00317                                  opts.ceil.rate);
00318         nla_put(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable);
00319 
00320         return msg;
00321 }
00322 
00323 /**
00324  * @name Attribute Modifications
00325  * @{
00326  */
00327 
00328 void rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum)
00329 {
00330         struct rtnl_htb_qdisc *d = htb_qdisc(qdisc);
00331         if (d == NULL)
00332                 return;
00333 
00334         d->qh_rate2quantum = rate2quantum;
00335         d->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM;
00336 }
00337 
00338 /**
00339  * Set default class of the htb qdisc to the specified value
00340  * @arg qdisc           qdisc to change
00341  * @arg defcls          new default class
00342  */
00343 void rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
00344 {
00345         struct rtnl_htb_qdisc *d = htb_qdisc(qdisc);
00346         if (d == NULL)
00347                 return;
00348 
00349         d->qh_defcls = defcls;
00350         d->qh_mask |= SCH_HTB_HAS_DEFCLS;
00351 }
00352 
00353 void rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio)
00354 {
00355         struct rtnl_htb_class *d = htb_class(class);
00356         if (d == NULL)
00357                 return;
00358 
00359         d->ch_prio = prio;
00360         d->ch_mask |= SCH_HTB_HAS_PRIO;
00361 }
00362 
00363 void rtnl_htb_set_mtu(struct rtnl_class *class, uint32_t mtu)
00364 {
00365         struct rtnl_htb_class *d = htb_class(class);
00366         if (d == NULL)
00367                 return;
00368 
00369         d->ch_mtu = mtu;
00370         d->ch_mask |= SCH_HTB_HAS_MTU;
00371 }
00372 
00373 void rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
00374 {
00375         struct rtnl_htb_class *d = htb_class(class);
00376         if (d == NULL)
00377                 return;
00378 
00379         d->ch_rate.rs_cell_log = UINT8_MAX; /* use default value */
00380         d->ch_rate.rs_rate = rate;
00381         d->ch_mask |= SCH_HTB_HAS_RATE;
00382 }
00383 
00384 void rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
00385 {
00386         struct rtnl_htb_class *d = htb_class(class);
00387         if (d == NULL)
00388                 return;
00389 
00390         d->ch_ceil.rs_cell_log = UINT8_MAX; /* use default value */
00391         d->ch_ceil.rs_rate = ceil;
00392         d->ch_mask |= SCH_HTB_HAS_CEIL;
00393 }
00394 
00395 /** @} */
00396 
00397 static struct rtnl_qdisc_ops htb_qdisc_ops = {
00398         .qo_kind                = "htb",
00399         .qo_msg_parser          = htb_qdisc_msg_parser,
00400         .qo_free_data           = htb_qdisc_free_data,
00401         .qo_dump[NL_DUMP_BRIEF] = htb_qdisc_dump_brief,
00402         .qo_get_opts            = htb_qdisc_get_opts,
00403 };
00404 
00405 static struct rtnl_class_ops htb_class_ops = {
00406         .co_kind                = "htb",
00407         .co_msg_parser          = htb_class_msg_parser,
00408         .co_free_data           = htb_class_free_data,
00409         .co_dump[NL_DUMP_BRIEF] = htb_class_dump_brief,
00410         .co_dump[NL_DUMP_FULL]  = htb_class_dump_full,
00411         .co_get_opts            = htb_class_get_opts,
00412 };
00413 
00414 static void __init htb_init(void)
00415 {
00416         rtnl_qdisc_register(&htb_qdisc_ops);
00417         rtnl_class_register(&htb_class_ops);
00418 }
00419 
00420 static void __exit htb_exit(void)
00421 {
00422         rtnl_qdisc_unregister(&htb_qdisc_ops);
00423         rtnl_class_unregister(&htb_class_ops);
00424 }
00425 
00426 /** @} */

Generated on Fri Apr 27 14:14:07 2007 for libnl by  doxygen 1.5.1