X-Git-Url: http://git.onelab.eu/?p=libnl.git;a=blobdiff_plain;f=lib%2Froute%2Fsch%2Ftbf.c;fp=lib%2Froute%2Fsch%2Ftbf.c;h=0000000000000000000000000000000000000000;hp=f3d50a53b79fd6043afb8defdfc86219641f4981;hb=332c8b7561dcac7ac95cc0d07328b1cb22d780a6;hpb=eabdd897b75ecc1fac5e255229a899126085e57a diff --git a/lib/route/sch/tbf.c b/lib/route/sch/tbf.c deleted file mode 100644 index f3d50a5..0000000 --- a/lib/route/sch/tbf.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * lib/route/sch/tbf.c TBF Qdisc - * - * 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 - */ - -/** - * @ingroup qdisc - * @defgroup tbf Token Bucket Filter (TBF) - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** @cond SKIP */ -#define TBF_ATTR_LIMIT 0x01 -#define TBF_ATTR_RATE 0x02 -#define TBF_ATTR_PEAKRATE 0x10 -#define TBF_ATTR_MPU 0x80 -/** @endcond */ - -static inline struct rtnl_tbf *tbf_qdisc(struct rtnl_qdisc *qdisc) -{ - return (struct rtnl_tbf *) qdisc->q_subdata; -} - -static inline struct rtnl_tbf *tbf_alloc(struct rtnl_qdisc *qdisc) -{ - if (!qdisc->q_subdata) - qdisc->q_subdata = calloc(1, sizeof(struct rtnl_tbf)); - - return tbf_qdisc(qdisc); -} - -static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = { - [TCA_TBF_PARMS] = { .minlen = sizeof(struct tc_tbf_qopt) }, -}; - -static int tbf_msg_parser(struct rtnl_qdisc *q) -{ - int err; - struct nlattr *tb[TCA_TBF_MAX + 1]; - struct rtnl_tbf *tbf; - - err = tca_parse(tb, TCA_TBF_MAX, (struct rtnl_tca *) q, tbf_policy); - if (err < 0) - return err; - - tbf = tbf_qdisc(q); - if (!tbf) - return nl_errno(ENOMEM); - - if (tb[TCA_TBF_PARMS]) { - struct tc_tbf_qopt opts; - int bufsize; - - nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts)); - tbf->qt_limit = opts.limit; - tbf->qt_mpu = opts.rate.mpu; - - rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate); - tbf->qt_rate_txtime = opts.buffer; - bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer), - opts.rate.rate); - tbf->qt_rate_bucket = bufsize; - - rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate); - tbf->qt_peakrate_txtime = opts.mtu; - bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu), - opts.peakrate.rate); - tbf->qt_peakrate_bucket = bufsize; - - tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_MPU | TBF_ATTR_RATE | - TBF_ATTR_PEAKRATE); - } - - return 0; -} - -static int tbf_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, - int line) -{ - double r, rbit, lim; - char *ru, *rubit, *limu; - struct rtnl_tbf *tbf = tbf_qdisc(qdisc); - - if (!tbf) - goto ignore; - - r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru); - rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit); - lim = nl_cancel_down_bytes(tbf->qt_limit, &limu); - - dp_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s", - r, ru, rbit, rubit, lim, limu); - -ignore: - return line; -} - -static int tbf_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p, - int line) -{ - struct rtnl_tbf *tbf = tbf_qdisc(qdisc); - - if (!tbf) - goto ignore; - - if (1) { - char *bu, *cu; - double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu); - double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log, - &cu); - - dp_dump(p, "mpu %u rate-bucket-size %1.f%s " - "rate-cell-size %.1f%s\n", - tbf->qt_mpu, bs, bu, cl, cu); - - } - - if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { - char *pru, *prbu, *bsu, *clu; - double pr, prb, bs, cl; - - pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru); - prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu); - bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu); - cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log, - &clu); - - dp_dump_line(p, line++, " peak-rate %.2f%s/s (%.0f%s) " - "bucket-size %.1f%s cell-size %.1f%s", - "latency %.1f%s", - pr, pru, prb, prbu, bs, bsu, cl, clu); - } - -ignore: - return line; -} - -static struct nl_msg *tbf_get_opts(struct rtnl_qdisc *qdisc) -{ - struct tc_tbf_qopt opts; - struct rtnl_tbf *tbf; - struct nl_msg *msg; - uint32_t rtab[RTNL_TC_RTABLE_SIZE]; - uint32_t ptab[RTNL_TC_RTABLE_SIZE]; - int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT; - - memset(&opts, 0, sizeof(opts)); - - tbf = tbf_qdisc(qdisc); - if (!tbf) - return NULL; - - if (!(tbf->qt_mask & required) != required) - return NULL; - - opts.limit = tbf->qt_limit; - opts.buffer = tbf->qt_rate_txtime; - tbf->qt_rate.rs_mpu = tbf->qt_mpu; - rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate); - - rtnl_tc_build_rate_table(rtab, tbf->qt_mpu & 0xff, tbf->qt_mpu >> 8, - 1 << tbf->qt_rate.rs_cell_log, - tbf->qt_rate.rs_rate); - - if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { - opts.mtu = tbf->qt_peakrate_txtime; - tbf->qt_peakrate.rs_mpu = tbf->qt_mpu; - rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate); - - rtnl_tc_build_rate_table(ptab, tbf->qt_mpu & 0xff, - tbf->qt_mpu >> 8, - 1 << tbf->qt_peakrate.rs_cell_log, - tbf->qt_peakrate.rs_rate); - } - - msg = nlmsg_build_no_hdr(); - if (!msg) - goto nla_put_failure; - - NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opts), &opts); - NLA_PUT(msg, TCA_TBF_RTAB, sizeof(rtab), rtab); - - if (tbf->qt_mask & TBF_ATTR_PEAKRATE) - NLA_PUT(msg, TCA_TBF_PTAB, sizeof(ptab), ptab); - - return msg; - -nla_put_failure: - nlmsg_free(msg); - return NULL; -} - -/** - * @name Attribute Access - * @{ - */ - -/** - * Set limit of TBF qdisc. - * @arg qdisc TBF qdisc to be modified. - * @arg limit New limit in bytes. - * @return 0 on success or a negative error code. - */ -int rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit) -{ - struct rtnl_tbf *tbf; - - tbf = tbf_alloc(qdisc); - if (!tbf) - return nl_errno(ENOMEM); - - tbf->qt_limit = limit; - tbf->qt_mask |= TBF_ATTR_LIMIT; - - return 0; -} - -static inline double calc_limit(struct rtnl_ratespec *spec, int latency, - int bucket) -{ - double limit; - - limit = (double) spec->rs_rate * ((double) latency / 1000000.); - limit += bucket; - - return limit; -} - -/** - * Set limit of TBF qdisc by latency. - * @arg qdisc TBF qdisc to be modified. - * @arg latency Latency in micro seconds. - * - * Calculates and sets the limit based on the desired latency and the - * configured rate and peak rate. In order for this operation to succeed, - * the rate and if required the peak rate must have been set in advance. - * - * @f[ - * limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n - * @f] - * @f[ - * limit = min(limit_{rate},limit_{peak}) - * @f] - * - * @return 0 on success or a negative error code. - */ -int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency) -{ - struct rtnl_tbf *tbf; - double limit, limit2; - - tbf = tbf_alloc(qdisc); - if (!tbf) - return nl_errno(ENOMEM); - - if (!(tbf->qt_mask & TBF_ATTR_RATE)) - return nl_error(EINVAL, "The rate must be specified before " - "limit can be calculated based on latency."); - - limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket); - - if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { - limit2 = calc_limit(&tbf->qt_peakrate, latency, - tbf->qt_peakrate_bucket); - - if (limit2 < limit) - limit = limit2; - } - - return rtnl_qdisc_tbf_set_limit(qdisc, (int) limit); -} - -/** - * Get limit of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Limit in bytes or a negative error code. - */ -int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_LIMIT)) - return tbf->qt_limit; - return - nl_errno(ENOENT); -} - -/** - * Set MPU of TBF qdisc. - * @arg qdisc TBF qdisc to be modified. - * @arg mpu New MPU in bytes. - * @return 0 on success or a negative error code. - */ -int rtnl_qdisc_tbf_set_mpu(struct rtnl_qdisc *qdisc, int mpu) -{ - struct rtnl_tbf *tbf; - - tbf = tbf_alloc(qdisc); - if (!tbf) - return nl_errno(ENOMEM); - - tbf->qt_mpu = mpu; - tbf->qt_mask |= TBF_ATTR_MPU; - - return 0; -} - -/** - * Get MPU of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return MPU in bytes or a negative error code. - */ -int rtnl_qdisc_tbf_get_mpu(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_MPU)) - return tbf->qt_mpu; - return - nl_errno(ENOENT); -} - -static inline int calc_cell_log(int cell, int bucket) -{ - if (cell > 0) - cell = rtnl_tc_calc_cell_log(cell); - else { - cell = 0; - - if (!bucket) - bucket = 2047; /* defaults to cell_log=3 */ - - while ((bucket >> cell) > 255) - cell++; - } - - return cell; -} - -/** - * Set rate of TBF qdisc. - * @arg qdisc TBF qdisc to be modified. - * @arg rate New rate in bytes per second. - * @arg bucket Size of bucket in bytes. - * @arg cell Size of a rate cell or 0 to get default value. - * @return 0 on success or a negative error code. - */ -int rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, - int cell) -{ - struct rtnl_tbf *tbf; - int cell_log; - - tbf = tbf_alloc(qdisc); - if (!tbf) - return nl_errno(ENOMEM); - - cell_log = calc_cell_log(cell, bucket); - if (cell_log < 0) - return cell_log; - - tbf->qt_rate.rs_rate = rate; - tbf->qt_rate_bucket = bucket; - tbf->qt_rate.rs_cell_log = cell_log; - tbf->qt_rate_txtime = rtnl_tc_calc_txtime(bucket, rate); - tbf->qt_mask |= TBF_ATTR_RATE; - - return 0; -} - -/** - * Get rate of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Rate in bytes per seconds or a negative error code. - */ -int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_RATE)) - return tbf->qt_rate.rs_rate; - else - return -1; -} - -/** - * Get rate bucket size of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Size of rate bucket or a negative error code. - */ -int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_RATE)) - return tbf->qt_rate_bucket; - else - return -1; -} - -/** - * Get rate cell size of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Size of rate cell in bytes or a negative error code. - */ -int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_RATE)) - return (1 << tbf->qt_rate.rs_cell_log); - else - return -1; -} - -/** - * Set peak rate of TBF qdisc. - * @arg qdisc TBF qdisc to be modified. - * @arg rate New peak rate in bytes per second. - * @arg bucket Size of peakrate bucket. - * @arg cell Size of a peakrate cell or 0 to get default value. - * @return 0 on success or a negative error code. - */ -int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket, - int cell) -{ - struct rtnl_tbf *tbf; - int cell_log; - - tbf = tbf_alloc(qdisc); - if (!tbf) - return nl_errno(ENOMEM); - - cell_log = calc_cell_log(cell, bucket); - if (cell_log < 0) - return cell_log; - - tbf->qt_peakrate.rs_rate = rate; - tbf->qt_peakrate_bucket = bucket; - tbf->qt_peakrate.rs_cell_log = cell_log; - tbf->qt_peakrate_txtime = rtnl_tc_calc_txtime(bucket, rate); - - tbf->qt_mask |= TBF_ATTR_PEAKRATE; - - return 0; -} - -/** - * Get peak rate of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Peak rate in bytes per seconds or a negative error code. - */ -int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE)) - return tbf->qt_peakrate.rs_rate; - else - return -1; -} - -/** - * Get peak rate bucket size of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Size of peak rate bucket or a negative error code. - */ -int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE)) - return tbf->qt_peakrate_bucket; - else - return -1; -} - -/** - * Get peak rate cell size of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Size of peak rate cell in bytes or a negative error code. - */ -int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE)) - return (1 << tbf->qt_peakrate.rs_cell_log); - else - return -1; -} - -/** @} */ - -static struct rtnl_qdisc_ops tbf_qdisc_ops = { - .qo_kind = "tbf", - .qo_msg_parser = tbf_msg_parser, - .qo_dump[NL_DUMP_BRIEF] = tbf_dump_brief, - .qo_dump[NL_DUMP_FULL] = tbf_dump_full, - .qo_get_opts = tbf_get_opts, -}; - -static void __init tbf_init(void) -{ - rtnl_qdisc_register(&tbf_qdisc_ops); -} - -static void __exit tbf_exit(void) -{ - rtnl_qdisc_unregister(&tbf_qdisc_ops); -} - -/** @} */