summaryrefslogtreecommitdiff
path: root/lib/route/qdisc/cbq.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/route/qdisc/cbq.c')
-rw-r--r--lib/route/qdisc/cbq.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/lib/route/qdisc/cbq.c b/lib/route/qdisc/cbq.c
new file mode 100644
index 0000000..e791a10
--- /dev/null
+++ b/lib/route/qdisc/cbq.c
@@ -0,0 +1,204 @@
+/*
+ * lib/route/qdisc/cbq.c Class Based Queueing
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink-tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc/cbq.h>
+#include <netlink/route/cls/police.h>
+
+/**
+ * @ingroup qdisc
+ * @ingroup class
+ * @defgroup qdisc_cbq Class Based Queueing (CBQ)
+ * @{
+ */
+
+static const struct trans_tbl ovl_strategies[] = {
+ __ADD(TC_CBQ_OVL_CLASSIC,classic)
+ __ADD(TC_CBQ_OVL_DELAY,delay)
+ __ADD(TC_CBQ_OVL_LOWPRIO,lowprio)
+ __ADD(TC_CBQ_OVL_DROP,drop)
+ __ADD(TC_CBQ_OVL_RCLASSIC,rclassic)
+};
+
+/**
+ * Convert a CBQ OVL strategy to a character string
+ * @arg type CBQ OVL strategy
+ * @arg buf destination buffer
+ * @arg len length of destination buffer
+ *
+ * Converts a CBQ OVL strategy to a character string and stores in the
+ * provided buffer. Returns the destination buffer or the type
+ * encoded in hex if no match was found.
+ */
+char *nl_ovl_strategy2str(int type, char *buf, size_t len)
+{
+ return __type2str(type, buf, len, ovl_strategies,
+ ARRAY_SIZE(ovl_strategies));
+}
+
+/**
+ * Convert a string to a CBQ OVL strategy
+ * @arg name CBQ OVL stragegy name
+ *
+ * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy
+ * type. Returns the type or -1 if none was found.
+ */
+int nl_str2ovl_strategy(const char *name)
+{
+ return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies));
+}
+
+static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = {
+ [TCA_CBQ_LSSOPT] = { .minlen = sizeof(struct tc_cbq_lssopt) },
+ [TCA_CBQ_RATE] = { .minlen = sizeof(struct tc_ratespec) },
+ [TCA_CBQ_WRROPT] = { .minlen = sizeof(struct tc_cbq_wrropt) },
+ [TCA_CBQ_OVL_STRATEGY] = { .minlen = sizeof(struct tc_cbq_ovl) },
+ [TCA_CBQ_FOPT] = { .minlen = sizeof(struct tc_cbq_fopt) },
+ [TCA_CBQ_POLICE] = { .minlen = sizeof(struct tc_cbq_police) },
+};
+
+static int cbq_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct nlattr *tb[TCA_CBQ_MAX + 1];
+ struct rtnl_cbq *cbq = data;
+ int err;
+
+ err = tca_parse(tb, TCA_CBQ_MAX, tc, cbq_policy);
+ if (err < 0)
+ return err;
+
+ nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss));
+ nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate));
+ nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr));
+ nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt));
+ nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY],
+ sizeof(cbq->cbq_ovl));
+ nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE],
+ sizeof(cbq->cbq_police));
+
+ return 0;
+}
+
+static void cbq_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_cbq *cbq = data;
+ double r, rbit;
+ char *ru, *rubit;
+
+ if (!cbq)
+ return;
+
+ r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru);
+ rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit);
+
+ nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
+ r, ru, rbit, rubit, cbq->cbq_wrr.priority);
+}
+
+static void cbq_dump_details(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_cbq *cbq = data;
+ char *unit, buf[32];
+ double w;
+ uint32_t el;
+
+ if (!cbq)
+ return;
+
+ w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit);
+
+ nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
+ cbq->cbq_lss.avpkt,
+ cbq->cbq_rate.mpu,
+ 1 << cbq->cbq_rate.cell_log,
+ cbq->cbq_wrr.allot, w, unit);
+
+ el = cbq->cbq_lss.ewma_log;
+ nl_dump_line(p, " minidle %uus maxidle %uus offtime "
+ "%uus level %u ewma_log %u\n",
+ nl_ticks2us(cbq->cbq_lss.minidle >> el),
+ nl_ticks2us(cbq->cbq_lss.maxidle >> el),
+ nl_ticks2us(cbq->cbq_lss.offtime >> el),
+ cbq->cbq_lss.level,
+ cbq->cbq_lss.ewma_log);
+
+ nl_dump_line(p, " penalty %uus strategy %s ",
+ nl_ticks2us(cbq->cbq_ovl.penalty),
+ nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf)));
+
+ nl_dump(p, "split %s defmap 0x%08x ",
+ rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)),
+ cbq->cbq_fopt.defmap);
+
+ nl_dump(p, "police %s",
+ nl_police2str(cbq->cbq_police.police, buf, sizeof(buf)));
+}
+
+static void cbq_dump_stats(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct tc_cbq_xstats *x;
+
+ if (!(x = tca_xstats(tc)))
+ return;
+
+ nl_dump_line(p, " borrows overact "
+ " avgidle undertime\n");
+ nl_dump_line(p, " %10u %10u %10u %10u\n",
+ x->borrows, x->overactions, x->avgidle, x->undertime);
+}
+
+static struct rtnl_tc_ops cbq_qdisc_ops = {
+ .to_kind = "cbq",
+ .to_type = RTNL_TC_TYPE_QDISC,
+ .to_size = sizeof(struct rtnl_cbq),
+ .to_msg_parser = cbq_msg_parser,
+ .to_dump = {
+ [NL_DUMP_LINE] = cbq_dump_line,
+ [NL_DUMP_DETAILS] = cbq_dump_details,
+ [NL_DUMP_STATS] = cbq_dump_stats,
+ },
+};
+
+static struct rtnl_tc_ops cbq_class_ops = {
+ .to_kind = "cbq",
+ .to_type = RTNL_TC_TYPE_CLASS,
+ .to_size = sizeof(struct rtnl_cbq),
+ .to_msg_parser = cbq_msg_parser,
+ .to_dump = {
+ [NL_DUMP_LINE] = cbq_dump_line,
+ [NL_DUMP_DETAILS] = cbq_dump_details,
+ [NL_DUMP_STATS] = cbq_dump_stats,
+ },
+};
+
+static void __init cbq_init(void)
+{
+ rtnl_tc_register(&cbq_qdisc_ops);
+ rtnl_tc_register(&cbq_class_ops);
+}
+
+static void __exit cbq_exit(void)
+{
+ rtnl_tc_unregister(&cbq_qdisc_ops);
+ rtnl_tc_unregister(&cbq_class_ops);
+}
+
+/** @} */