X-Git-Url: http://git.onelab.eu/?p=libnl.git;a=blobdiff_plain;f=lib%2Froute%2Fsch%2Fcbq.c;fp=lib%2Froute%2Fsch%2Fcbq.c;h=59f6951e82feac649b3df58556cb67cb78d220ae;hp=0000000000000000000000000000000000000000;hb=4cee2ecb3b8afa0637e6f5fe4c57985a4bc740ff;hpb=2df2fbe518d5a221ce6e3ee88a3fb23fb1b94b27 diff --git a/lib/route/sch/cbq.c b/lib/route/sch/cbq.c new file mode 100644 index 0000000..59f6951 --- /dev/null +++ b/lib/route/sch/cbq.c @@ -0,0 +1,284 @@ +/* + * lib/route/sch/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-2006 Thomas Graf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @ingroup qdisc + * @ingroup class + * @defgroup cbq Class Based Queueing (CBQ) + * @{ + */ + +static 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 inline struct rtnl_cbq *cbq_qdisc(struct rtnl_tca *tca) +{ + return (struct rtnl_cbq *) tca->tc_subdata; +} + +static inline struct rtnl_cbq *cbq_alloc(struct rtnl_tca *tca) +{ + if (!tca->tc_subdata) + tca->tc_subdata = calloc(1, sizeof(struct rtnl_qdisc)); + + return cbq_qdisc(tca); +} + + +static int cbq_msg_parser(struct rtnl_tca *tca) +{ + struct nlattr *tb[TCA_CBQ_MAX + 1]; + struct rtnl_cbq *cbq; + int err; + + err = tca_parse(tb, TCA_CBQ_MAX, tca, cbq_policy); + if (err < 0) + return err; + + cbq = cbq_alloc(tca); + if (!cbq) + return nl_errno(ENOMEM); + + 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 int cbq_qdisc_msg_parser(struct rtnl_qdisc *qdisc) +{ + return cbq_msg_parser((struct rtnl_tca *) qdisc); +} + +static int cbq_class_msg_parser(struct rtnl_class *class) +{ + return cbq_msg_parser((struct rtnl_tca *) class); +} + +static void cbq_qdisc_free_data(struct rtnl_qdisc *qdisc) +{ + free(qdisc->q_subdata); +} + +static void cbq_class_free_data(struct rtnl_class *class) +{ + free(class->c_subdata); +} + +static int cbq_dump_brief(struct rtnl_tca *tca, struct nl_dump_params *p, + int line) +{ + struct rtnl_cbq *cbq; + double r, rbit; + char *ru, *rubit; + + cbq = cbq_qdisc(tca); + if (!cbq) + goto ignore; + + r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru); + rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit); + + dp_dump(p, " rate %.2f%s/s (%.0f%s) prio %u", + r, ru, rbit, rubit, cbq->cbq_wrr.priority); + +ignore: + return line; +} + +static int cbq_qdisc_dump_brief(struct rtnl_qdisc *qdisc, + struct nl_dump_params *p, int line) +{ + return cbq_dump_brief((struct rtnl_tca *) qdisc, p, line); +} + +static int cbq_class_dump_brief(struct rtnl_class *class, + struct nl_dump_params *p, int line) +{ + return cbq_dump_brief((struct rtnl_tca *) class, p, line); +} + +static int cbq_dump_full(struct rtnl_tca *tca, struct nl_dump_params *p, + int line) +{ + struct rtnl_cbq *cbq; + char *unit, buf[32]; + double w; + uint32_t el; + + cbq = cbq_qdisc(tca); + if (!cbq) + goto ignore; + + w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit); + + dp_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; + dp_dump_line(p, line++, " 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); + + dp_dump_line(p, line++, " penalty %uus strategy %s ", + nl_ticks2us(cbq->cbq_ovl.penalty), + nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf))); + + dp_dump(p, "split %s defmap 0x%08x ", + rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)), + cbq->cbq_fopt.defmap); + + dp_dump(p, "police %s", + nl_police2str(cbq->cbq_police.police, buf, sizeof(buf))); + +ignore: + return line; +} + +static int cbq_qdisc_dump_full(struct rtnl_qdisc *qdisc, + struct nl_dump_params *p, int line) +{ + return cbq_dump_full((struct rtnl_tca *) qdisc, p, line); +} + +static int cbq_class_dump_full(struct rtnl_class *class, + struct nl_dump_params *p, int line) +{ + return cbq_dump_full((struct rtnl_tca *) class, p, line); +} + +static int cbq_dump_with_stats(struct rtnl_tca *tca, struct nl_dump_params *p, + int line) +{ + struct tc_cbq_xstats *x = tca_xstats(tca); + + if (!x) + goto ignore; + + dp_dump_line(p, line++, " borrows overact " + " avgidle undertime\n"); + dp_dump_line(p, line++, " %10u %10u %10u %10u\n", + x->borrows, x->overactions, x->avgidle, x->undertime); + +ignore: + return line; +} + +static int cbq_qdisc_dump_with_stats(struct rtnl_qdisc *qdisc, + struct nl_dump_params *p, int line) +{ + return cbq_dump_with_stats((struct rtnl_tca *) qdisc, p, line); +} + +static int cbq_class_dump_with_stats(struct rtnl_class *class, + struct nl_dump_params *p, int line) +{ + return cbq_dump_with_stats((struct rtnl_tca *) class, p, line); +} + +static struct rtnl_qdisc_ops cbq_qdisc_ops = { + .qo_kind = "cbq", + .qo_msg_parser = cbq_qdisc_msg_parser, + .qo_free_data = cbq_qdisc_free_data, + .qo_dump[NL_DUMP_BRIEF] = cbq_qdisc_dump_brief, + .qo_dump[NL_DUMP_FULL] = cbq_qdisc_dump_full, + .qo_dump[NL_DUMP_STATS] = cbq_qdisc_dump_with_stats, +}; + +static struct rtnl_class_ops cbq_class_ops = { + .co_kind = "cbq", + .co_msg_parser = cbq_class_msg_parser, + .co_free_data = cbq_class_free_data, + .co_dump[NL_DUMP_BRIEF] = cbq_class_dump_brief, + .co_dump[NL_DUMP_FULL] = cbq_class_dump_full, + .co_dump[NL_DUMP_STATS] = cbq_class_dump_with_stats, +}; + +static void __init cbq_init(void) +{ + rtnl_qdisc_register(&cbq_qdisc_ops); + rtnl_class_register(&cbq_class_ops); +} + +static void __exit cbq_exit(void) +{ + rtnl_qdisc_unregister(&cbq_qdisc_ops); + rtnl_class_unregister(&cbq_class_ops); +} + +/** @} */