libnl 2.0

/tmp/buildd/libnl2-2.0/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-2008 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 -NLE_NOMEM;
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 -NLE_NOMEM;
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 void cbq_dump_line(struct rtnl_tca *tca, struct nl_dump_params *p)
00157 {
00158         struct rtnl_cbq *cbq;
00159         double r, rbit;
00160         char *ru, *rubit;
00161 
00162         cbq = cbq_qdisc(tca);
00163         if (!cbq)
00164                 return;
00165 
00166         r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru);
00167         rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit);
00168 
00169         nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
00170                 r, ru, rbit, rubit, cbq->cbq_wrr.priority);
00171 }
00172 
00173 static void cbq_qdisc_dump_line(struct rtnl_qdisc *qdisc,
00174                                 struct nl_dump_params *p)
00175 {
00176         cbq_dump_line((struct rtnl_tca *) qdisc, p);
00177 }
00178 
00179 static void cbq_class_dump_line(struct rtnl_class *class,
00180                                 struct nl_dump_params *p)
00181 {
00182         cbq_dump_line((struct rtnl_tca *) class, p);
00183 }
00184 
00185 static void cbq_dump_details(struct rtnl_tca *tca, struct nl_dump_params *p)
00186 {
00187         struct rtnl_cbq *cbq;
00188         char *unit, buf[32];
00189         double w;
00190         uint32_t el;
00191 
00192         cbq = cbq_qdisc(tca);
00193         if (!cbq)
00194                 return;
00195 
00196         w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit);
00197 
00198         nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
00199                 cbq->cbq_lss.avpkt,
00200                 cbq->cbq_rate.mpu,
00201                 1 << cbq->cbq_rate.cell_log,
00202                 cbq->cbq_wrr.allot, w, unit);
00203 
00204         el = cbq->cbq_lss.ewma_log;
00205         nl_dump_line(p, "  minidle %uus maxidle %uus offtime "
00206                                 "%uus level %u ewma_log %u\n",
00207                 nl_ticks2us(cbq->cbq_lss.minidle >> el),
00208                 nl_ticks2us(cbq->cbq_lss.maxidle >> el),
00209                 nl_ticks2us(cbq->cbq_lss.offtime >> el),
00210                 cbq->cbq_lss.level,
00211                 cbq->cbq_lss.ewma_log);
00212 
00213         nl_dump_line(p, "  penalty %uus strategy %s ",
00214                 nl_ticks2us(cbq->cbq_ovl.penalty),
00215                 nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf)));
00216 
00217         nl_dump(p, "split %s defmap 0x%08x ",
00218                 rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)),
00219                 cbq->cbq_fopt.defmap);
00220         
00221         nl_dump(p, "police %s",
00222                 nl_police2str(cbq->cbq_police.police, buf, sizeof(buf)));
00223 }
00224 
00225 static void cbq_qdisc_dump_details(struct rtnl_qdisc *qdisc,
00226                                    struct nl_dump_params *p)
00227 {
00228         cbq_dump_details((struct rtnl_tca *) qdisc, p);
00229 }
00230 
00231 static void cbq_class_dump_details(struct rtnl_class *class,
00232                                    struct nl_dump_params *p)
00233 {
00234         cbq_dump_details((struct rtnl_tca *) class, p);
00235 }
00236 
00237 static void cbq_dump_stats(struct rtnl_tca *tca, struct nl_dump_params *p)
00238 {
00239         struct tc_cbq_xstats *x = tca_xstats(tca);
00240 
00241         if (!x)
00242                 return;
00243 
00244         nl_dump_line(p, "            borrows    overact  "
00245                         "  avgidle  undertime\n");
00246         nl_dump_line(p, "         %10u %10u %10u %10u\n",
00247                      x->borrows, x->overactions, x->avgidle, x->undertime);
00248 }
00249 
00250 static void cbq_qdisc_dump_stats(struct rtnl_qdisc *qdisc,
00251                                  struct nl_dump_params *p)
00252 {
00253         cbq_dump_stats((struct rtnl_tca *) qdisc, p);
00254 }
00255 
00256 static void cbq_class_dump_stats(struct rtnl_class *class,
00257                                  struct nl_dump_params *p)
00258 {
00259         cbq_dump_stats((struct rtnl_tca *) class, p);
00260 }
00261 
00262 static struct rtnl_qdisc_ops cbq_qdisc_ops = {
00263         .qo_kind                = "cbq",
00264         .qo_msg_parser          = cbq_qdisc_msg_parser,
00265         .qo_free_data           = cbq_qdisc_free_data,
00266         .qo_clone               = cbq_qdisc_clone,
00267         .qo_dump = {
00268             [NL_DUMP_LINE]      = cbq_qdisc_dump_line,
00269             [NL_DUMP_DETAILS]   = cbq_qdisc_dump_details,
00270             [NL_DUMP_STATS]     = cbq_qdisc_dump_stats,
00271         },
00272 };
00273 
00274 static struct rtnl_class_ops cbq_class_ops = {
00275         .co_kind                = "cbq",
00276         .co_msg_parser          = cbq_class_msg_parser,
00277         .co_free_data           = cbq_class_free_data,
00278         .co_clone               = cbq_class_clone,
00279         .co_dump = {
00280             [NL_DUMP_LINE]      = cbq_class_dump_line,
00281             [NL_DUMP_DETAILS]   = cbq_class_dump_details,
00282             [NL_DUMP_STATS]     = cbq_class_dump_stats,
00283         },
00284 };
00285 
00286 static void __init cbq_init(void)
00287 {
00288         rtnl_qdisc_register(&cbq_qdisc_ops);
00289         rtnl_class_register(&cbq_class_ops);
00290 }
00291 
00292 static void __exit cbq_exit(void)
00293 {
00294         rtnl_qdisc_unregister(&cbq_qdisc_ops);
00295         rtnl_class_unregister(&cbq_class_ops);
00296 }
00297 
00298 /** @} */