00001
00002
00003
00004
00005
00006
00007
00008
00009
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
00026
00027
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
00041
00042
00043
00044
00045
00046
00047
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
00057
00058
00059
00060
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