diff options
Diffstat (limited to 'lib/route/qdisc/cbq.c')
-rw-r--r-- | lib/route/qdisc/cbq.c | 204 |
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); +} + +/** @} */ |