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/tc-api.h>
00017 #include <netlink/route/qdisc.h>
00018 #include <netlink/route/class.h>
00019 #include <netlink/route/link.h>
00020 #include <netlink/route/qdisc/cbq.h>
00021 #include <netlink/route/cls/police.h>
00022
00023
00024
00025
00026
00027
00028
00029
00030 static const struct trans_tbl ovl_strategies[] = {
00031 __ADD(TC_CBQ_OVL_CLASSIC,classic)
00032 __ADD(TC_CBQ_OVL_DELAY,delay)
00033 __ADD(TC_CBQ_OVL_LOWPRIO,lowprio)
00034 __ADD(TC_CBQ_OVL_DROP,drop)
00035 __ADD(TC_CBQ_OVL_RCLASSIC,rclassic)
00036 };
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 char *nl_ovl_strategy2str(int type, char *buf, size_t len)
00049 {
00050 return __type2str(type, buf, len, ovl_strategies,
00051 ARRAY_SIZE(ovl_strategies));
00052 }
00053
00054
00055
00056
00057
00058
00059
00060
00061 int nl_str2ovl_strategy(const char *name)
00062 {
00063 return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies));
00064 }
00065
00066 static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = {
00067 [TCA_CBQ_LSSOPT] = { .minlen = sizeof(struct tc_cbq_lssopt) },
00068 [TCA_CBQ_RATE] = { .minlen = sizeof(struct tc_ratespec) },
00069 [TCA_CBQ_WRROPT] = { .minlen = sizeof(struct tc_cbq_wrropt) },
00070 [TCA_CBQ_OVL_STRATEGY] = { .minlen = sizeof(struct tc_cbq_ovl) },
00071 [TCA_CBQ_FOPT] = { .minlen = sizeof(struct tc_cbq_fopt) },
00072 [TCA_CBQ_POLICE] = { .minlen = sizeof(struct tc_cbq_police) },
00073 };
00074
00075 static int cbq_msg_parser(struct rtnl_tc *tc, void *data)
00076 {
00077 struct nlattr *tb[TCA_CBQ_MAX + 1];
00078 struct rtnl_cbq *cbq = data;
00079 int err;
00080
00081 err = tca_parse(tb, TCA_CBQ_MAX, tc, cbq_policy);
00082 if (err < 0)
00083 return err;
00084
00085 nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss));
00086 nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate));
00087 nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr));
00088 nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt));
00089 nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY],
00090 sizeof(cbq->cbq_ovl));
00091 nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE],
00092 sizeof(cbq->cbq_police));
00093
00094 return 0;
00095 }
00096
00097 static void cbq_dump_line(struct rtnl_tc *tc, void *data,
00098 struct nl_dump_params *p)
00099 {
00100 struct rtnl_cbq *cbq = data;
00101 double r, rbit;
00102 char *ru, *rubit;
00103
00104 if (!cbq)
00105 return;
00106
00107 r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru);
00108 rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit);
00109
00110 nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
00111 r, ru, rbit, rubit, cbq->cbq_wrr.priority);
00112 }
00113
00114 static void cbq_dump_details(struct rtnl_tc *tc, void *data,
00115 struct nl_dump_params *p)
00116 {
00117 struct rtnl_cbq *cbq = data;
00118 char *unit, buf[32];
00119 double w;
00120 uint32_t el;
00121
00122 if (!cbq)
00123 return;
00124
00125 w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit);
00126
00127 nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
00128 cbq->cbq_lss.avpkt,
00129 cbq->cbq_rate.mpu,
00130 1 << cbq->cbq_rate.cell_log,
00131 cbq->cbq_wrr.allot, w, unit);
00132
00133 el = cbq->cbq_lss.ewma_log;
00134 nl_dump_line(p, " minidle %uus maxidle %uus offtime "
00135 "%uus level %u ewma_log %u\n",
00136 nl_ticks2us(cbq->cbq_lss.minidle >> el),
00137 nl_ticks2us(cbq->cbq_lss.maxidle >> el),
00138 nl_ticks2us(cbq->cbq_lss.offtime >> el),
00139 cbq->cbq_lss.level,
00140 cbq->cbq_lss.ewma_log);
00141
00142 nl_dump_line(p, " penalty %uus strategy %s ",
00143 nl_ticks2us(cbq->cbq_ovl.penalty),
00144 nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf)));
00145
00146 nl_dump(p, "split %s defmap 0x%08x ",
00147 rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)),
00148 cbq->cbq_fopt.defmap);
00149
00150 nl_dump(p, "police %s",
00151 nl_police2str(cbq->cbq_police.police, buf, sizeof(buf)));
00152 }
00153
00154 static void cbq_dump_stats(struct rtnl_tc *tc, void *data,
00155 struct nl_dump_params *p)
00156 {
00157 struct tc_cbq_xstats *x;
00158
00159 if (!(x = tca_xstats(tc)))
00160 return;
00161
00162 nl_dump_line(p, " borrows overact "
00163 " avgidle undertime\n");
00164 nl_dump_line(p, " %10u %10u %10u %10u\n",
00165 x->borrows, x->overactions, x->avgidle, x->undertime);
00166 }
00167
00168 static struct rtnl_tc_ops cbq_qdisc_ops = {
00169 .to_kind = "cbq",
00170 .to_type = RTNL_TC_TYPE_QDISC,
00171 .to_size = sizeof(struct rtnl_cbq),
00172 .to_msg_parser = cbq_msg_parser,
00173 .to_dump = {
00174 [NL_DUMP_LINE] = cbq_dump_line,
00175 [NL_DUMP_DETAILS] = cbq_dump_details,
00176 [NL_DUMP_STATS] = cbq_dump_stats,
00177 },
00178 };
00179
00180 static struct rtnl_tc_ops cbq_class_ops = {
00181 .to_kind = "cbq",
00182 .to_type = RTNL_TC_TYPE_CLASS,
00183 .to_size = sizeof(struct rtnl_cbq),
00184 .to_msg_parser = cbq_msg_parser,
00185 .to_dump = {
00186 [NL_DUMP_LINE] = cbq_dump_line,
00187 [NL_DUMP_DETAILS] = cbq_dump_details,
00188 [NL_DUMP_STATS] = cbq_dump_stats,
00189 },
00190 };
00191
00192 static void __init cbq_init(void)
00193 {
00194 rtnl_tc_register(&cbq_qdisc_ops);
00195 rtnl_tc_register(&cbq_class_ops);
00196 }
00197
00198 static void __exit cbq_exit(void)
00199 {
00200 rtnl_tc_unregister(&cbq_qdisc_ops);
00201 rtnl_tc_unregister(&cbq_class_ops);
00202 }
00203
00204