144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/route/sch/tbf.c		TBF Qdisc
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
98a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf
1244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
1344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @ingroup qdisc_api
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @defgroup tbf Token Bucket Filter (TBF)
1544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
1944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-tc.h>
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/cache.h>
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h>
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/tc.h>
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/qdisc.h>
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/qdisc-modules.h>
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/class.h>
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/class-modules.h>
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/link.h>
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/sch/tbf.h>
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @cond SKIP */
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define TBF_ATTR_LIMIT			0x01
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define TBF_ATTR_RATE			0x02
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define TBF_ATTR_PEAKRATE		0x10
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define TBF_ATTR_MPU			0x80
3644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @endcond */
3744d362409d5469aed47d19e7908d19bd194493aThomas Graf
3844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline struct rtnl_tbf *tbf_qdisc(struct rtnl_qdisc *qdisc)
3944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (struct rtnl_tbf *) qdisc->q_subdata;
4144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
4244d362409d5469aed47d19e7908d19bd194493aThomas Graf
4344d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline struct rtnl_tbf *tbf_alloc(struct rtnl_qdisc *qdisc)
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!qdisc->q_subdata)
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf		qdisc->q_subdata = calloc(1, sizeof(struct rtnl_tbf));
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf
4844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return tbf_qdisc(qdisc);
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf
5144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy tbf_policy[TCA_TBF_MAX+1] = {
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_TBF_PARMS]	= { .minlen = sizeof(struct tc_tbf_qopt) },
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf};
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf
5544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int tbf_msg_parser(struct rtnl_qdisc *q)
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[TCA_TBF_MAX + 1];
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = tca_parse(tb, TCA_TBF_MAX, (struct rtnl_tca *) q, tbf_policy);
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
6444d362409d5469aed47d19e7908d19bd194493aThomas Graf
65241b2b83ba5672f5c86154d29eeb8ef4c7c6e9b4Tad Kollar	tbf = tbf_alloc(q);
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!tbf)
678a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf
6944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_TBF_PARMS]) {
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct tc_tbf_qopt opts;
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf		int bufsize;
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf
7344d362409d5469aed47d19e7908d19bd194493aThomas Graf		nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts));
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf		tbf->qt_limit = opts.limit;
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf		tbf->qt_mpu = opts.rate.mpu;
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate);
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf		tbf->qt_rate_txtime = opts.buffer;
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf		bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf					       opts.rate.rate);
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf		tbf->qt_rate_bucket = bufsize;
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate);
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf		tbf->qt_peakrate_txtime = opts.mtu;
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf		bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu),
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf					       opts.peakrate.rate);
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf		tbf->qt_peakrate_bucket = bufsize;
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf
8944d362409d5469aed47d19e7908d19bd194493aThomas Graf		tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_MPU | TBF_ATTR_RATE |
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf				TBF_ATTR_PEAKRATE);
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
9244d362409d5469aed47d19e7908d19bd194493aThomas Graf
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
9544d362409d5469aed47d19e7908d19bd194493aThomas Graf
9686b6f6f6291eaaec542a2f4028087fa823122082Denys Fedorysychenkostatic void tbf_free_data(struct rtnl_qdisc *qdisc)
9786b6f6f6291eaaec542a2f4028087fa823122082Denys Fedorysychenko{
9886b6f6f6291eaaec542a2f4028087fa823122082Denys Fedorysychenko	free(qdisc->q_subdata);
9986b6f6f6291eaaec542a2f4028087fa823122082Denys Fedorysychenko}
10086b6f6f6291eaaec542a2f4028087fa823122082Denys Fedorysychenko
101d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void tbf_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf	double r, rbit, lim;
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf	char *ru, *rubit, *limu;
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf = tbf_qdisc(qdisc);
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!tbf)
108d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		return;
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf	r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru);
11144d362409d5469aed47d19e7908d19bd194493aThomas Graf	rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit);
11244d362409d5469aed47d19e7908d19bd194493aThomas Graf	lim = nl_cancel_down_bytes(tbf->qt_limit, &limu);
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf
114d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s",
11544d362409d5469aed47d19e7908d19bd194493aThomas Graf		r, ru, rbit, rubit, lim, limu);
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf
118d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void tbf_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf = tbf_qdisc(qdisc);
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!tbf)
123d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		return;
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf
12544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (1) {
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf		char *bu, *cu;
12744d362409d5469aed47d19e7908d19bd194493aThomas Graf		double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu);
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf		double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log,
12944d362409d5469aed47d19e7908d19bd194493aThomas Graf						 &cu);
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf
131d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "mpu %u rate-bucket-size %1.f%s "
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf			   "rate-cell-size %.1f%s\n",
13344d362409d5469aed47d19e7908d19bd194493aThomas Graf			tbf->qt_mpu, bs, bu, cl, cu);
13444d362409d5469aed47d19e7908d19bd194493aThomas Graf
13544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
13644d362409d5469aed47d19e7908d19bd194493aThomas Graf
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
13844d362409d5469aed47d19e7908d19bd194493aThomas Graf		char *pru, *prbu, *bsu, *clu;
13944d362409d5469aed47d19e7908d19bd194493aThomas Graf		double pr, prb, bs, cl;
14044d362409d5469aed47d19e7908d19bd194493aThomas Graf
14144d362409d5469aed47d19e7908d19bd194493aThomas Graf		pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru);
14244d362409d5469aed47d19e7908d19bd194493aThomas Graf		prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu);
14344d362409d5469aed47d19e7908d19bd194493aThomas Graf		bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu);
14444d362409d5469aed47d19e7908d19bd194493aThomas Graf		cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log,
14544d362409d5469aed47d19e7908d19bd194493aThomas Graf					 &clu);
14644d362409d5469aed47d19e7908d19bd194493aThomas Graf
147d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump_line(p, "    peak-rate %.2f%s/s (%.0f%s) "
14852510e7d394a1c8ee0a3aaf046db6199f0558c78Denys Fedoryschenko				"bucket-size %.1f%s cell-size %.1f%s"
149d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf				"latency %.1f%s",
15044d362409d5469aed47d19e7908d19bd194493aThomas Graf			     pr, pru, prb, prbu, bs, bsu, cl, clu);
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
15244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf
15444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_msg *tbf_get_opts(struct rtnl_qdisc *qdisc)
15544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
15644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tc_tbf_qopt opts;
15744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t rtab[RTNL_TC_RTABLE_SIZE];
16044d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t ptab[RTNL_TC_RTABLE_SIZE];
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf	int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf	memset(&opts, 0, sizeof(opts));
16444d362409d5469aed47d19e7908d19bd194493aThomas Graf
16544d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_qdisc(qdisc);
16644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!tbf)
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
16844d362409d5469aed47d19e7908d19bd194493aThomas Graf
16944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!(tbf->qt_mask & required) != required)
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
17144d362409d5469aed47d19e7908d19bd194493aThomas Graf
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf	opts.limit = tbf->qt_limit;
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf	opts.buffer = tbf->qt_rate_txtime;
17444d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_rate.rs_mpu = tbf->qt_mpu;
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate);
17644d362409d5469aed47d19e7908d19bd194493aThomas Graf
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_tc_build_rate_table(rtab, tbf->qt_mpu & 0xff, tbf->qt_mpu >> 8,
17844d362409d5469aed47d19e7908d19bd194493aThomas Graf				 1 << tbf->qt_rate.rs_cell_log,
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf				 tbf->qt_rate.rs_rate);
18044d362409d5469aed47d19e7908d19bd194493aThomas Graf
18144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf		opts.mtu = tbf->qt_peakrate_txtime;
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf		tbf->qt_peakrate.rs_mpu = tbf->qt_mpu;
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate);
18544d362409d5469aed47d19e7908d19bd194493aThomas Graf
18644d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_tc_build_rate_table(ptab, tbf->qt_mpu & 0xff,
18744d362409d5469aed47d19e7908d19bd194493aThomas Graf					 tbf->qt_mpu >> 8,
18844d362409d5469aed47d19e7908d19bd194493aThomas Graf					 1 << tbf->qt_peakrate.rs_cell_log,
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf					 tbf->qt_peakrate.rs_rate);
19044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
19144d362409d5469aed47d19e7908d19bd194493aThomas Graf
19244d362409d5469aed47d19e7908d19bd194493aThomas Graf	msg = nlmsg_alloc();
19344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!msg)
19444d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto nla_put_failure;
19544d362409d5469aed47d19e7908d19bd194493aThomas Graf
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf	NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opts), &opts);
19744d362409d5469aed47d19e7908d19bd194493aThomas Graf	NLA_PUT(msg, TCA_TBF_RTAB, sizeof(rtab), rtab);
19844d362409d5469aed47d19e7908d19bd194493aThomas Graf
19944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf		NLA_PUT(msg, TCA_TBF_PTAB, sizeof(ptab), ptab);
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf
20244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return msg;
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf
20444d362409d5469aed47d19e7908d19bd194493aThomas Grafnla_put_failure:
20544d362409d5469aed47d19e7908d19bd194493aThomas Graf	nlmsg_free(msg);
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NULL;
20744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
21044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Attribute Access
21144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
21244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf
21444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
21544d362409d5469aed47d19e7908d19bd194493aThomas Graf * Set limit of TBF qdisc.
21644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc to be modified.
21744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg limit		New limit in bytes.
21844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code.
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf */
22044d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit)
22144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
22244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf
22444d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_alloc(qdisc);
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!tbf)
2268a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf
22844d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_limit = limit;
22944d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_mask |= TBF_ATTR_LIMIT;
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf
23144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
23244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
23344d362409d5469aed47d19e7908d19bd194493aThomas Graf
23444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline double calc_limit(struct rtnl_ratespec *spec, int latency,
23544d362409d5469aed47d19e7908d19bd194493aThomas Graf				int bucket)
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf	double limit;
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf
23944d362409d5469aed47d19e7908d19bd194493aThomas Graf	limit = (double) spec->rs_rate * ((double) latency / 1000000.);
24044d362409d5469aed47d19e7908d19bd194493aThomas Graf	limit += bucket;
24144d362409d5469aed47d19e7908d19bd194493aThomas Graf
24244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return limit;
24344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
24444d362409d5469aed47d19e7908d19bd194493aThomas Graf
24544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
24644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Set limit of TBF qdisc by latency.
24744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc to be modified.
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg latency		Latency in micro seconds.
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
25044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Calculates and sets the limit based on the desired latency and the
25144d362409d5469aed47d19e7908d19bd194493aThomas Graf * configured rate and peak rate. In order for this operation to succeed,
25244d362409d5469aed47d19e7908d19bd194493aThomas Graf * the rate and if required the peak rate must have been set in advance.
25344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
25444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @f[
25544d362409d5469aed47d19e7908d19bd194493aThomas Graf *   limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n
25644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @f]
25744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @f[
25844d362409d5469aed47d19e7908d19bd194493aThomas Graf *   limit = min(limit_{rate},limit_{peak})
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @f]
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code.
26244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
26344d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency)
26444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf	double limit, limit2;
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_alloc(qdisc);
26944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!tbf)
2708a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
27144d362409d5469aed47d19e7908d19bd194493aThomas Graf
27244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!(tbf->qt_mask & TBF_ATTR_RATE))
2738a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_MISSING_ATTR;
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf
27544d362409d5469aed47d19e7908d19bd194493aThomas Graf	limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket);
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf
27744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
27844d362409d5469aed47d19e7908d19bd194493aThomas Graf		limit2 = calc_limit(&tbf->qt_peakrate, latency,
27944d362409d5469aed47d19e7908d19bd194493aThomas Graf				    tbf->qt_peakrate_bucket);
28044d362409d5469aed47d19e7908d19bd194493aThomas Graf
28144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (limit2 < limit)
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf			limit = limit2;
28344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
28444d362409d5469aed47d19e7908d19bd194493aThomas Graf
28544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return rtnl_qdisc_tbf_set_limit(qdisc, (int) limit);
28644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf
28844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
28944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get limit of TBF qdisc.
29044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc.
29144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Limit in bytes or a negative error code.
29244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
29344d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc)
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
29544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
29644d362409d5469aed47d19e7908d19bd194493aThomas Graf
29744d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_qdisc(qdisc);
29844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf && (tbf->qt_mask & TBF_ATTR_LIMIT))
29944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return tbf->qt_limit;
3008a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	else
3018a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOATTR;
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
30344d362409d5469aed47d19e7908d19bd194493aThomas Graf
30444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
30544d362409d5469aed47d19e7908d19bd194493aThomas Graf * Set MPU of TBF qdisc.
30644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc to be modified.
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg mpu		New MPU in bytes.
30844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code.
30944d362409d5469aed47d19e7908d19bd194493aThomas Graf */
31044d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_set_mpu(struct rtnl_qdisc *qdisc, int mpu)
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
31244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf
31444d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_alloc(qdisc);
31544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!tbf)
3168a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
31744d362409d5469aed47d19e7908d19bd194493aThomas Graf
31844d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_mpu = mpu;
31944d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_mask |= TBF_ATTR_MPU;
32044d362409d5469aed47d19e7908d19bd194493aThomas Graf
32144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
32244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf
32444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
32544d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get MPU of TBF qdisc.
32644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc.
32744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return MPU in bytes or a negative error code.
32844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
32944d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_get_mpu(struct rtnl_qdisc *qdisc)
33044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
33244d362409d5469aed47d19e7908d19bd194493aThomas Graf
33344d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_qdisc(qdisc);
33444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf && (tbf->qt_mask & TBF_ATTR_MPU))
33544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return tbf->qt_mpu;
3368a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	else
3378a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOATTR;
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
33944d362409d5469aed47d19e7908d19bd194493aThomas Graf
34044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline int calc_cell_log(int cell, int bucket)
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cell > 0)
34344d362409d5469aed47d19e7908d19bd194493aThomas Graf		cell = rtnl_tc_calc_cell_log(cell);
34444d362409d5469aed47d19e7908d19bd194493aThomas Graf	else {
34544d362409d5469aed47d19e7908d19bd194493aThomas Graf		cell = 0;
34644d362409d5469aed47d19e7908d19bd194493aThomas Graf
34744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!bucket)
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf			bucket = 2047; /* defaults to cell_log=3 */
34944d362409d5469aed47d19e7908d19bd194493aThomas Graf
35044d362409d5469aed47d19e7908d19bd194493aThomas Graf		while ((bucket >> cell) > 255)
35144d362409d5469aed47d19e7908d19bd194493aThomas Graf			cell++;
35244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
35344d362409d5469aed47d19e7908d19bd194493aThomas Graf
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return cell;
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf
35744d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Set rate of TBF qdisc.
35944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc to be modified.
36044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg rate		New rate in bytes per second.
36144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg bucket		Size of bucket in bytes.
36244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cell		Size of a rate cell or 0 to get default value.
36344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code.
36444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
36544d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf			    int cell)
36744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf	int cell_log;
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf
37144d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_alloc(qdisc);
37244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!tbf)
3738a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf
37544d362409d5469aed47d19e7908d19bd194493aThomas Graf	cell_log = calc_cell_log(cell, bucket);
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cell_log < 0)
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return cell_log;
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_rate.rs_rate = rate;
38044d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_rate_bucket = bucket;
38144d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_rate.rs_cell_log = cell_log;
38244d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_rate_txtime = rtnl_tc_calc_txtime(bucket, rate);
38344d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_mask |= TBF_ATTR_RATE;
38444d362409d5469aed47d19e7908d19bd194493aThomas Graf
38544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
38644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
38744d362409d5469aed47d19e7908d19bd194493aThomas Graf
38844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
38944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get rate of TBF qdisc.
39044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc.
39144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Rate in bytes per seconds or a negative error code.
39244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
39344d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc)
39444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
39544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
39644d362409d5469aed47d19e7908d19bd194493aThomas Graf
39744d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_qdisc(qdisc);
39844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf && (tbf->qt_mask & TBF_ATTR_RATE))
39944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return tbf->qt_rate.rs_rate;
40044d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
40144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
40244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
40344d362409d5469aed47d19e7908d19bd194493aThomas Graf
40444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
40544d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get rate bucket size of TBF qdisc.
40644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc.
40744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Size of rate bucket or a negative error code.
40844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
40944d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc)
41044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
41144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
41244d362409d5469aed47d19e7908d19bd194493aThomas Graf
41344d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_qdisc(qdisc);
41444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf && (tbf->qt_mask & TBF_ATTR_RATE))
41544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return tbf->qt_rate_bucket;
41644d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
41744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
41844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
41944d362409d5469aed47d19e7908d19bd194493aThomas Graf
42044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get rate cell size of TBF qdisc.
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc.
42344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Size of rate cell in bytes or a negative error code.
42444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
42544d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc)
42644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
42744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
42844d362409d5469aed47d19e7908d19bd194493aThomas Graf
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_qdisc(qdisc);
43044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf && (tbf->qt_mask & TBF_ATTR_RATE))
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return (1 << tbf->qt_rate.rs_cell_log);
43244d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
43444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
43544d362409d5469aed47d19e7908d19bd194493aThomas Graf
43644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
43744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Set peak rate of TBF qdisc.
43844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc to be modified.
43944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg rate		New peak rate in bytes per second.
44044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg bucket		Size of peakrate bucket.
44144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cell		Size of a peakrate cell or 0 to get default value.
44244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code.
44344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
44444d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
44544d362409d5469aed47d19e7908d19bd194493aThomas Graf				int cell)
44644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
44744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
44844d362409d5469aed47d19e7908d19bd194493aThomas Graf	int cell_log;
44944d362409d5469aed47d19e7908d19bd194493aThomas Graf
45044d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_alloc(qdisc);
45144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!tbf)
4528a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
45344d362409d5469aed47d19e7908d19bd194493aThomas Graf
45444d362409d5469aed47d19e7908d19bd194493aThomas Graf	cell_log = calc_cell_log(cell, bucket);
45544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cell_log < 0)
45644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return cell_log;
45744d362409d5469aed47d19e7908d19bd194493aThomas Graf
45844d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_peakrate.rs_rate = rate;
45944d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_peakrate_bucket = bucket;
46044d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_peakrate.rs_cell_log = cell_log;
46144d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_peakrate_txtime = rtnl_tc_calc_txtime(bucket, rate);
46244d362409d5469aed47d19e7908d19bd194493aThomas Graf
46344d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf->qt_mask |= TBF_ATTR_PEAKRATE;
46444d362409d5469aed47d19e7908d19bd194493aThomas Graf
46544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
46644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
46744d362409d5469aed47d19e7908d19bd194493aThomas Graf
46844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
46944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get peak rate of TBF qdisc.
47044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc.
47144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Peak rate in bytes per seconds or a negative error code.
47244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
47344d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc)
47444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
47544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
47644d362409d5469aed47d19e7908d19bd194493aThomas Graf
47744d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_qdisc(qdisc);
47844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE))
47944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return tbf->qt_peakrate.rs_rate;
48044d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
48144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
48244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
48344d362409d5469aed47d19e7908d19bd194493aThomas Graf
48444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
48544d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get peak rate bucket size of TBF qdisc.
48644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc.
48744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Size of peak rate bucket or a negative error code.
48844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
48944d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc)
49044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
49144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
49244d362409d5469aed47d19e7908d19bd194493aThomas Graf
49344d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_qdisc(qdisc);
49444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE))
49544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return tbf->qt_peakrate_bucket;
49644d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
49744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
49844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
49944d362409d5469aed47d19e7908d19bd194493aThomas Graf
50044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
50144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get peak rate cell size of TBF qdisc.
50244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		TBF qdisc.
50344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Size of peak rate cell in bytes or a negative error code.
50444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
50544d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc)
50644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
50744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tbf *tbf;
50844d362409d5469aed47d19e7908d19bd194493aThomas Graf
50944d362409d5469aed47d19e7908d19bd194493aThomas Graf	tbf = tbf_qdisc(qdisc);
51044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE))
51144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return (1 << tbf->qt_peakrate.rs_cell_log);
51244d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
51344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return -1;
51444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
51544d362409d5469aed47d19e7908d19bd194493aThomas Graf
51644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
51744d362409d5469aed47d19e7908d19bd194493aThomas Graf
51844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct rtnl_qdisc_ops tbf_qdisc_ops = {
51944d362409d5469aed47d19e7908d19bd194493aThomas Graf	.qo_kind		= "tbf",
52044d362409d5469aed47d19e7908d19bd194493aThomas Graf	.qo_msg_parser		= tbf_msg_parser,
521d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	.qo_dump = {
522d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_LINE]	= tbf_dump_line,
523d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_DETAILS]	= tbf_dump_details,
524d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	},
52586b6f6f6291eaaec542a2f4028087fa823122082Denys Fedorysychenko	.qo_free_data		= tbf_free_data,
52644d362409d5469aed47d19e7908d19bd194493aThomas Graf	.qo_get_opts		= tbf_get_opts,
52744d362409d5469aed47d19e7908d19bd194493aThomas Graf};
52844d362409d5469aed47d19e7908d19bd194493aThomas Graf
52944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __init tbf_init(void)
53044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
53144d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_qdisc_register(&tbf_qdisc_ops);
53244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
53344d362409d5469aed47d19e7908d19bd194493aThomas Graf
53444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __exit tbf_exit(void)
53544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
53644d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_qdisc_unregister(&tbf_qdisc_ops);
53744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
53844d362409d5469aed47d19e7908d19bd194493aThomas Graf
53944d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
540