libnl 1.1

lib/route/sch/cbq.c

00001 /*
00002  * lib/route/sch/cbq.c  Class Based Queueing
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  */
00011 
00012 #include <netlink-local.h>
00013 #include <netlink-tc.h>
00014 #include <netlink/netlink.h>
00015 #include <netlink/utils.h>
00016 #include <netlink/route/qdisc.h>
00017 #include <netlink/route/qdisc-modules.h>
00018 #include <netlink/route/class.h>
00019 #include <netlink/route/class-modules.h>
00020 #include <netlink/route/link.h>
00021 #include <netlink/route/sch/cbq.h>
00022 #include <netlink/route/cls/police.h>
00023 
00024 /**
00025  * @ingroup qdisc_api
00026  * @ingroup class_api
00027  * @defgroup cbq Class Based Queueing (CBQ)
00028  * @{
00029  */
00030 
00031 static struct trans_tbl ovl_strategies[] = {
00032         __ADD(TC_CBQ_OVL_CLASSIC,classic)
00033         __ADD(TC_CBQ_OVL_DELAY,delay)
00034         __ADD(TC_CBQ_OVL_LOWPRIO,lowprio)
00035         __ADD(TC_CBQ_OVL_DROP,drop)
00036         __ADD(TC_CBQ_OVL_RCLASSIC,rclassic)
00037 };
00038 
00039 /**
00040  * Convert a CBQ OVL strategy to a character string
00041  * @arg type            CBQ OVL strategy
00042  * @arg buf             destination buffer
00043  * @arg len             length of destination buffer
00044  *
00045  * Converts a CBQ OVL strategy to a character string and stores in the
00046  * provided buffer. Returns the destination buffer or the type
00047  * encoded in hex if no match was found.
00048  */
00049 char *nl_ovl_strategy2str(int type, char *buf, size_t len)
00050 {
00051         return __type2str(type, buf, len, ovl_strategies,
00052                             ARRAY_SIZE(ovl_strategies));
00053 }
00054 
00055 /**
00056  * Convert a string to a CBQ OVL strategy
00057  * @arg name            CBQ OVL stragegy name
00058  *
00059  * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy
00060  * type. Returns the type or -1 if none was found.
00061  */
00062 int nl_str2ovl_strategy(const char *name)
00063 {
00064         return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies));
00065 }
00066 
00067 static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = {
00068         [TCA_CBQ_LSSOPT]        = { .minlen = sizeof(struct tc_cbq_lssopt) },
00069         [TCA_CBQ_RATE]          = { .minlen = sizeof(struct tc_ratespec) },
00070         [TCA_CBQ_WRROPT]        = { .minlen = sizeof(struct tc_cbq_wrropt) },
00071         [TCA_CBQ_OVL_STRATEGY]  = { .minlen = sizeof(struct tc_cbq_ovl) },
00072         [TCA_CBQ_FOPT]          = { .minlen = sizeof(struct tc_cbq_fopt) },
00073         [TCA_CBQ_POLICE]        = { .minlen = sizeof(struct tc_cbq_police) },
00074 };
00075 
00076 static inline struct rtnl_cbq *cbq_qdisc(struct rtnl_tca *tca)
00077 {
00078         return (struct rtnl_cbq *) tca->tc_subdata;
00079 }
00080 
00081 static inline struct rtnl_cbq *cbq_alloc(struct rtnl_tca *tca)
00082 {
00083         if (!tca->tc_subdata)
00084                 tca->tc_subdata = calloc(1, sizeof(struct rtnl_qdisc));
00085 
00086         return cbq_qdisc(tca);
00087 }
00088 
00089 
00090 static int cbq_msg_parser(struct rtnl_tca *tca)
00091 {
00092         struct nlattr *tb[TCA_CBQ_MAX + 1];
00093         struct rtnl_cbq *cbq;
00094         int err;
00095 
00096         err = tca_parse(tb, TCA_CBQ_MAX, tca, cbq_policy);
00097         if (err < 0)
00098                 return err;
00099 
00100         cbq = cbq_alloc(tca);
00101         if (!cbq)
00102                 return nl_errno(ENOMEM);
00103 
00104         nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss));
00105         nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate));
00106         nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr));
00107         nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt));
00108         nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY],
00109                    sizeof(cbq->cbq_ovl));
00110         nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE],
00111                     sizeof(cbq->cbq_police));
00112         
00113         return 0;
00114 }
00115 
00116 static int cbq_qdisc_msg_parser(struct rtnl_qdisc *qdisc)
00117 {
00118         return cbq_msg_parser((struct rtnl_tca *) qdisc);
00119 }
00120 
00121 static int cbq_class_msg_parser(struct rtnl_class *class)
00122 {
00123         return cbq_msg_parser((struct rtnl_tca *) class);
00124 }
00125 
00126 static void cbq_qdisc_free_data(struct rtnl_qdisc *qdisc)
00127 {
00128         free(qdisc->q_subdata);
00129 }
00130 
00131 static int cbq_clone(struct rtnl_tca *_dst, struct rtnl_tca *_src)
00132 {
00133         struct rtnl_cbq *src = cbq_qdisc(_src);
00134 
00135         if (src && !cbq_alloc(_dst))
00136                 return nl_errno(ENOMEM);
00137         else
00138                 return 0;
00139 }
00140 
00141 static int cbq_qdisc_clone(struct rtnl_qdisc *dst, struct rtnl_qdisc *src)
00142 {
00143         return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src);
00144 }
00145 
00146 static void cbq_class_free_data(struct rtnl_class *class)
00147 {
00148         free(class->c_subdata);
00149 }
00150 
00151 static int cbq_class_clone(struct rtnl_class *dst, struct rtnl_class *src)
00152 {
00153         return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src);
00154 }
00155 
00156 static int cbq_dump_brief(struct rtnl_tca *tca, struct nl_dump_params *p,
00157                           int line)
00158 {
00159         struct rtnl_cbq *cbq;
00160         double r, rbit;
00161         char *ru, *rubit;
00162 
00163         cbq = cbq_qdisc(tca);
00164         if (!cbq)
00165                 goto ignore;
00166 
00167         r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru);
00168         rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit);
00169 
00170         dp_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
00171                 r, ru, rbit, rubit, cbq->cbq_wrr.priority);
00172 
00173 ignore:
00174         return line;
00175 }
00176 
00177 static int cbq_qdisc_dump_brief(struct rtnl_qdisc *qdisc,
00178                                 struct nl_dump_params *p, int line)
00179 {
00180         return cbq_dump_brief((struct rtnl_tca *) qdisc, p, line);
00181 }
00182 
00183 static int cbq_class_dump_brief(struct rtnl_class *class,
00184                                 struct nl_dump_params *p, int line)
00185 {
00186         return cbq_dump_brief((struct rtnl_tca *) class, p, line);
00187 }
00188 
00189 static int cbq_dump_full(struct rtnl_tca *tca, struct nl_dump_params *p,
00190                          int line)
00191 {
00192         struct rtnl_cbq *cbq;
00193         char *unit, buf[32];
00194         double w;
00195         uint32_t el;
00196 
00197         cbq = cbq_qdisc(tca);
00198         if (!cbq)
00199                 goto ignore;
00200 
00201         w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit);
00202 
00203         dp_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
00204                 cbq->cbq_lss.avpkt,
00205                 cbq->cbq_rate.mpu,
00206                 1 << cbq->cbq_rate.cell_log,
00207                 cbq->cbq_wrr.allot, w, unit);
00208 
00209         el = cbq->cbq_lss.ewma_log;
00210         dp_dump_line(p, line++, "  minidle %uus maxidle %uus offtime "
00211                                 "%uus level %u ewma_log %u\n",
00212                 nl_ticks2us(cbq->cbq_lss.minidle >> el),
00213                 nl_ticks2us(cbq->cbq_lss.maxidle >> el),
00214                 nl_ticks2us(cbq->cbq_lss.offtime >> el),
00215                 cbq->cbq_lss.level,
00216                 cbq->cbq_lss.ewma_log);
00217 
00218         dp_dump_line(p, line++, "  penalty %uus strategy %s ",
00219                 nl_ticks2us(cbq->cbq_ovl.penalty),
00220                 nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf)));
00221 
00222         dp_dump(p, "split %s defmap 0x%08x ",
00223                 rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)),
00224                 cbq->cbq_fopt.defmap);
00225         
00226         dp_dump(p, "police %s",
00227                 nl_police2str(cbq->cbq_police.police, buf, sizeof(buf)));
00228 
00229 ignore:
00230         return line;
00231 }
00232 
00233 static int cbq_qdisc_dump_full(struct rtnl_qdisc *qdisc,
00234                                struct nl_dump_params *p, int line)
00235 {
00236         return cbq_dump_full((struct rtnl_tca *) qdisc, p, line);
00237 }
00238 
00239 static int cbq_class_dump_full(struct rtnl_class *class,
00240                                struct nl_dump_params *p, int line)
00241 {
00242         return cbq_dump_full((struct rtnl_tca *) class, p, line);
00243 }
00244 
00245 static int cbq_dump_with_stats(struct rtnl_tca *tca, struct nl_dump_params *p,
00246                                int line)
00247 {
00248         struct tc_cbq_xstats *x = tca_xstats(tca);
00249 
00250         if (!x)
00251                 goto ignore;
00252 
00253         dp_dump_line(p, line++, "            borrows    overact  "
00254                                 "  avgidle  undertime\n");
00255         dp_dump_line(p, line++, "         %10u %10u %10u %10u\n",
00256                      x->borrows, x->overactions, x->avgidle, x->undertime);
00257 
00258 ignore:
00259         return line;
00260 }
00261 
00262 static int cbq_qdisc_dump_with_stats(struct rtnl_qdisc *qdisc,
00263                                      struct nl_dump_params *p, int line)
00264 {
00265         return cbq_dump_with_stats((struct rtnl_tca *) qdisc, p, line);
00266 }
00267 
00268 static int cbq_class_dump_with_stats(struct rtnl_class *class,
00269                                      struct nl_dump_params *p, int line)
00270 {
00271         return cbq_dump_with_stats((struct rtnl_tca *) class, p, line);
00272 }
00273 
00274 static struct rtnl_qdisc_ops cbq_qdisc_ops = {
00275         .qo_kind                = "cbq",
00276         .qo_msg_parser          = cbq_qdisc_msg_parser,
00277         .qo_free_data           = cbq_qdisc_free_data,
00278         .qo_clone               = cbq_qdisc_clone,
00279         .qo_dump[NL_DUMP_BRIEF] = cbq_qdisc_dump_brief,
00280         .qo_dump[NL_DUMP_FULL]  = cbq_qdisc_dump_full,
00281         .qo_dump[NL_DUMP_STATS] = cbq_qdisc_dump_with_stats,
00282 };
00283 
00284 static struct rtnl_class_ops cbq_class_ops = {
00285         .co_kind                = "cbq",
00286         .co_msg_parser          = cbq_class_msg_parser,
00287         .co_free_data           = cbq_class_free_data,
00288         .co_clone               = cbq_class_clone,
00289         .co_dump[NL_DUMP_BRIEF] = cbq_class_dump_brief,
00290         .co_dump[NL_DUMP_FULL]  = cbq_class_dump_full,
00291         .co_dump[NL_DUMP_STATS] = cbq_class_dump_with_stats,
00292 };
00293 
00294 static void __init cbq_init(void)
00295 {
00296         rtnl_qdisc_register(&cbq_qdisc_ops);
00297         rtnl_class_register(&cbq_class_ops);
00298 }
00299 
00300 static void __exit cbq_exit(void)
00301 {
00302         rtnl_qdisc_unregister(&cbq_qdisc_ops);
00303         rtnl_class_unregister(&cbq_class_ops);
00304 }
00305 
00306 /** @} */