xref: /aosp_15_r20/external/libnl/lib/route/qdisc/tbf.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1*4dc78e53SAndroid Build Coastguard Worker /* SPDX-License-Identifier: LGPL-2.1-only */
2*4dc78e53SAndroid Build Coastguard Worker /*
3*4dc78e53SAndroid Build Coastguard Worker  * Copyright (c) 2003-2011 Thomas Graf <[email protected]>
4*4dc78e53SAndroid Build Coastguard Worker  */
5*4dc78e53SAndroid Build Coastguard Worker 
6*4dc78e53SAndroid Build Coastguard Worker /**
7*4dc78e53SAndroid Build Coastguard Worker  * @ingroup qdisc
8*4dc78e53SAndroid Build Coastguard Worker  * @defgroup qdisc_tbf Token Bucket Filter (TBF)
9*4dc78e53SAndroid Build Coastguard Worker  * @{
10*4dc78e53SAndroid Build Coastguard Worker  */
11*4dc78e53SAndroid Build Coastguard Worker 
12*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
13*4dc78e53SAndroid Build Coastguard Worker 
14*4dc78e53SAndroid Build Coastguard Worker #include <netlink/netlink.h>
15*4dc78e53SAndroid Build Coastguard Worker #include <netlink/cache.h>
16*4dc78e53SAndroid Build Coastguard Worker #include <netlink/utils.h>
17*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/qdisc.h>
18*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/class.h>
19*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/link.h>
20*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/qdisc/tbf.h>
21*4dc78e53SAndroid Build Coastguard Worker 
22*4dc78e53SAndroid Build Coastguard Worker #include "tc-api.h"
23*4dc78e53SAndroid Build Coastguard Worker 
24*4dc78e53SAndroid Build Coastguard Worker /** @cond SKIP */
25*4dc78e53SAndroid Build Coastguard Worker struct rtnl_tbf {
26*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qt_limit;
27*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ratespec qt_rate;
28*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qt_rate_bucket;
29*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qt_rate_txtime;
30*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_ratespec qt_peakrate;
31*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qt_peakrate_bucket;
32*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qt_peakrate_txtime;
33*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qt_mask;
34*4dc78e53SAndroid Build Coastguard Worker };
35*4dc78e53SAndroid Build Coastguard Worker 
36*4dc78e53SAndroid Build Coastguard Worker #define TBF_ATTR_LIMIT			0x01
37*4dc78e53SAndroid Build Coastguard Worker #define TBF_ATTR_RATE			0x02
38*4dc78e53SAndroid Build Coastguard Worker #define TBF_ATTR_PEAKRATE		0x10
39*4dc78e53SAndroid Build Coastguard Worker /** @endcond */
40*4dc78e53SAndroid Build Coastguard Worker 
41*4dc78e53SAndroid Build Coastguard Worker static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = {
42*4dc78e53SAndroid Build Coastguard Worker 	[TCA_TBF_PARMS]	= { .minlen = sizeof(struct tc_tbf_qopt) },
43*4dc78e53SAndroid Build Coastguard Worker };
44*4dc78e53SAndroid Build Coastguard Worker 
tbf_msg_parser(struct rtnl_tc * tc,void * data)45*4dc78e53SAndroid Build Coastguard Worker static int tbf_msg_parser(struct rtnl_tc *tc, void *data)
46*4dc78e53SAndroid Build Coastguard Worker {
47*4dc78e53SAndroid Build Coastguard Worker 	struct nlattr *tb[TCA_TBF_MAX + 1];
48*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf = data;
49*4dc78e53SAndroid Build Coastguard Worker 	int err;
50*4dc78e53SAndroid Build Coastguard Worker 
51*4dc78e53SAndroid Build Coastguard Worker 	if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0)
52*4dc78e53SAndroid Build Coastguard Worker 		return err;
53*4dc78e53SAndroid Build Coastguard Worker 
54*4dc78e53SAndroid Build Coastguard Worker 	if (tb[TCA_TBF_PARMS]) {
55*4dc78e53SAndroid Build Coastguard Worker 		struct tc_tbf_qopt opts;
56*4dc78e53SAndroid Build Coastguard Worker 		int bufsize;
57*4dc78e53SAndroid Build Coastguard Worker 
58*4dc78e53SAndroid Build Coastguard Worker 		nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts));
59*4dc78e53SAndroid Build Coastguard Worker 		tbf->qt_limit = opts.limit;
60*4dc78e53SAndroid Build Coastguard Worker 
61*4dc78e53SAndroid Build Coastguard Worker 		rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate);
62*4dc78e53SAndroid Build Coastguard Worker 		tbf->qt_rate_txtime = opts.buffer;
63*4dc78e53SAndroid Build Coastguard Worker 		bufsize = rtnl_tc_calc_bufsize64(nl_ticks2us(opts.buffer),
64*4dc78e53SAndroid Build Coastguard Worker 		                                 tbf->qt_rate.rs_rate64);
65*4dc78e53SAndroid Build Coastguard Worker 		tbf->qt_rate_bucket = bufsize;
66*4dc78e53SAndroid Build Coastguard Worker 
67*4dc78e53SAndroid Build Coastguard Worker 		rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate);
68*4dc78e53SAndroid Build Coastguard Worker 		tbf->qt_peakrate_txtime = opts.mtu;
69*4dc78e53SAndroid Build Coastguard Worker 		bufsize = rtnl_tc_calc_bufsize64(nl_ticks2us(opts.mtu),
70*4dc78e53SAndroid Build Coastguard Worker 		                                 tbf->qt_peakrate.rs_rate64);
71*4dc78e53SAndroid Build Coastguard Worker 		tbf->qt_peakrate_bucket = bufsize;
72*4dc78e53SAndroid Build Coastguard Worker 
73*4dc78e53SAndroid Build Coastguard Worker 		rtnl_tc_set_mpu(tc, tbf->qt_rate.rs_mpu);
74*4dc78e53SAndroid Build Coastguard Worker 		rtnl_tc_set_overhead(tc, tbf->qt_rate.rs_overhead);
75*4dc78e53SAndroid Build Coastguard Worker 
76*4dc78e53SAndroid Build Coastguard Worker 		tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_RATE | TBF_ATTR_PEAKRATE);
77*4dc78e53SAndroid Build Coastguard Worker 	}
78*4dc78e53SAndroid Build Coastguard Worker 
79*4dc78e53SAndroid Build Coastguard Worker 	return 0;
80*4dc78e53SAndroid Build Coastguard Worker }
81*4dc78e53SAndroid Build Coastguard Worker 
tbf_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)82*4dc78e53SAndroid Build Coastguard Worker static void tbf_dump_line(struct rtnl_tc *tc, void *data,
83*4dc78e53SAndroid Build Coastguard Worker 			  struct nl_dump_params *p)
84*4dc78e53SAndroid Build Coastguard Worker {
85*4dc78e53SAndroid Build Coastguard Worker 	double r, rbit, lim;
86*4dc78e53SAndroid Build Coastguard Worker 	char *ru, *rubit, *limu;
87*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf = data;
88*4dc78e53SAndroid Build Coastguard Worker 
89*4dc78e53SAndroid Build Coastguard Worker 	if (!tbf)
90*4dc78e53SAndroid Build Coastguard Worker 		return;
91*4dc78e53SAndroid Build Coastguard Worker 
92*4dc78e53SAndroid Build Coastguard Worker 	r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate64, &ru);
93*4dc78e53SAndroid Build Coastguard Worker 	rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate64*8, &rubit);
94*4dc78e53SAndroid Build Coastguard Worker 	lim = nl_cancel_down_bytes(tbf->qt_limit, &limu);
95*4dc78e53SAndroid Build Coastguard Worker 
96*4dc78e53SAndroid Build Coastguard Worker 	nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s",
97*4dc78e53SAndroid Build Coastguard Worker 		r, ru, rbit, rubit, lim, limu);
98*4dc78e53SAndroid Build Coastguard Worker }
99*4dc78e53SAndroid Build Coastguard Worker 
tbf_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)100*4dc78e53SAndroid Build Coastguard Worker static void tbf_dump_details(struct rtnl_tc *tc, void *data,
101*4dc78e53SAndroid Build Coastguard Worker 			     struct nl_dump_params *p)
102*4dc78e53SAndroid Build Coastguard Worker {
103*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf = data;
104*4dc78e53SAndroid Build Coastguard Worker 
105*4dc78e53SAndroid Build Coastguard Worker 	if (!tbf)
106*4dc78e53SAndroid Build Coastguard Worker 		return;
107*4dc78e53SAndroid Build Coastguard Worker 
108*4dc78e53SAndroid Build Coastguard Worker 	if (1) {
109*4dc78e53SAndroid Build Coastguard Worker 		char *bu, *cu;
110*4dc78e53SAndroid Build Coastguard Worker 		double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu);
111*4dc78e53SAndroid Build Coastguard Worker 		double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log,
112*4dc78e53SAndroid Build Coastguard Worker 						 &cu);
113*4dc78e53SAndroid Build Coastguard Worker 
114*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "rate-bucket-size %1.f%s "
115*4dc78e53SAndroid Build Coastguard Worker 			   "rate-cell-size %.1f%s\n",
116*4dc78e53SAndroid Build Coastguard Worker 			bs, bu, cl, cu);
117*4dc78e53SAndroid Build Coastguard Worker 
118*4dc78e53SAndroid Build Coastguard Worker 	}
119*4dc78e53SAndroid Build Coastguard Worker 
120*4dc78e53SAndroid Build Coastguard Worker 	if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
121*4dc78e53SAndroid Build Coastguard Worker 		char *pru, *prbu, *bsu, *clu;
122*4dc78e53SAndroid Build Coastguard Worker 		double pr, prb, bs, cl;
123*4dc78e53SAndroid Build Coastguard Worker 
124*4dc78e53SAndroid Build Coastguard Worker 		pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate64, &pru);
125*4dc78e53SAndroid Build Coastguard Worker 		prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate64 * 8, &prbu);
126*4dc78e53SAndroid Build Coastguard Worker 		bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu);
127*4dc78e53SAndroid Build Coastguard Worker 		cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log,
128*4dc78e53SAndroid Build Coastguard Worker 					 &clu);
129*4dc78e53SAndroid Build Coastguard Worker 
130*4dc78e53SAndroid Build Coastguard Worker 		nl_dump_line(p,
131*4dc78e53SAndroid Build Coastguard Worker 			     "    peak-rate %.2f%s/s (%.0f%s) "
132*4dc78e53SAndroid Build Coastguard Worker 			     "bucket-size %.1f%s cell-size %.1f%s",
133*4dc78e53SAndroid Build Coastguard Worker 			     pr, pru, prb, prbu, bs, bsu, cl, clu);
134*4dc78e53SAndroid Build Coastguard Worker 	}
135*4dc78e53SAndroid Build Coastguard Worker }
136*4dc78e53SAndroid Build Coastguard Worker 
tbf_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)137*4dc78e53SAndroid Build Coastguard Worker static int tbf_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
138*4dc78e53SAndroid Build Coastguard Worker {
139*4dc78e53SAndroid Build Coastguard Worker 	uint32_t rtab[RTNL_TC_RTABLE_SIZE], ptab[RTNL_TC_RTABLE_SIZE];
140*4dc78e53SAndroid Build Coastguard Worker 	struct tc_tbf_qopt opts;
141*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf = data;
142*4dc78e53SAndroid Build Coastguard Worker 	const uint32_t REQUIRED = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
143*4dc78e53SAndroid Build Coastguard Worker 
144*4dc78e53SAndroid Build Coastguard Worker 	if ((tbf->qt_mask & REQUIRED) != REQUIRED)
145*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MISSING_ATTR;
146*4dc78e53SAndroid Build Coastguard Worker 
147*4dc78e53SAndroid Build Coastguard Worker 	memset(&opts, 0, sizeof(opts));
148*4dc78e53SAndroid Build Coastguard Worker 	opts.limit = tbf->qt_limit;
149*4dc78e53SAndroid Build Coastguard Worker 	opts.buffer = tbf->qt_rate_txtime;
150*4dc78e53SAndroid Build Coastguard Worker 
151*4dc78e53SAndroid Build Coastguard Worker 	rtnl_tc_build_rate_table(tc, &tbf->qt_rate, rtab);
152*4dc78e53SAndroid Build Coastguard Worker 	rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate);
153*4dc78e53SAndroid Build Coastguard Worker 
154*4dc78e53SAndroid Build Coastguard Worker 	if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
155*4dc78e53SAndroid Build Coastguard Worker 		opts.mtu = tbf->qt_peakrate_txtime;
156*4dc78e53SAndroid Build Coastguard Worker 		rtnl_tc_build_rate_table(tc, &tbf->qt_peakrate, ptab);
157*4dc78e53SAndroid Build Coastguard Worker 		rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate);
158*4dc78e53SAndroid Build Coastguard Worker 
159*4dc78e53SAndroid Build Coastguard Worker 	}
160*4dc78e53SAndroid Build Coastguard Worker 
161*4dc78e53SAndroid Build Coastguard Worker 	NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opts), &opts);
162*4dc78e53SAndroid Build Coastguard Worker 	NLA_PUT(msg, TCA_TBF_RTAB, sizeof(rtab), rtab);
163*4dc78e53SAndroid Build Coastguard Worker 
164*4dc78e53SAndroid Build Coastguard Worker 	if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
165*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT(msg, TCA_TBF_PTAB, sizeof(ptab), ptab);
166*4dc78e53SAndroid Build Coastguard Worker 
167*4dc78e53SAndroid Build Coastguard Worker 	return 0;
168*4dc78e53SAndroid Build Coastguard Worker 
169*4dc78e53SAndroid Build Coastguard Worker nla_put_failure:
170*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_MSGSIZE;
171*4dc78e53SAndroid Build Coastguard Worker }
172*4dc78e53SAndroid Build Coastguard Worker 
173*4dc78e53SAndroid Build Coastguard Worker /**
174*4dc78e53SAndroid Build Coastguard Worker  * @name Attribute Access
175*4dc78e53SAndroid Build Coastguard Worker  * @{
176*4dc78e53SAndroid Build Coastguard Worker  */
177*4dc78e53SAndroid Build Coastguard Worker 
178*4dc78e53SAndroid Build Coastguard Worker /**
179*4dc78e53SAndroid Build Coastguard Worker  * Set limit of TBF qdisc.
180*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		TBF qdisc to be modified.
181*4dc78e53SAndroid Build Coastguard Worker  * @arg limit		New limit in bytes.
182*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
183*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc * qdisc,int limit)184*4dc78e53SAndroid Build Coastguard Worker void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit)
185*4dc78e53SAndroid Build Coastguard Worker {
186*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf;
187*4dc78e53SAndroid Build Coastguard Worker 
188*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
189*4dc78e53SAndroid Build Coastguard Worker 		BUG();
190*4dc78e53SAndroid Build Coastguard Worker 
191*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_limit = limit;
192*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_mask |= TBF_ATTR_LIMIT;
193*4dc78e53SAndroid Build Coastguard Worker }
194*4dc78e53SAndroid Build Coastguard Worker 
calc_limit(struct rtnl_ratespec * spec,int latency,int bucket)195*4dc78e53SAndroid Build Coastguard Worker static inline double calc_limit(struct rtnl_ratespec *spec, int latency,
196*4dc78e53SAndroid Build Coastguard Worker 				int bucket)
197*4dc78e53SAndroid Build Coastguard Worker {
198*4dc78e53SAndroid Build Coastguard Worker 	double limit;
199*4dc78e53SAndroid Build Coastguard Worker 
200*4dc78e53SAndroid Build Coastguard Worker 	limit = (double) spec->rs_rate64 * ((double) latency / 1000000.);
201*4dc78e53SAndroid Build Coastguard Worker 	limit += bucket;
202*4dc78e53SAndroid Build Coastguard Worker 
203*4dc78e53SAndroid Build Coastguard Worker 	return limit;
204*4dc78e53SAndroid Build Coastguard Worker }
205*4dc78e53SAndroid Build Coastguard Worker 
206*4dc78e53SAndroid Build Coastguard Worker /**
207*4dc78e53SAndroid Build Coastguard Worker  * Set limit of TBF qdisc by latency.
208*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		TBF qdisc to be modified.
209*4dc78e53SAndroid Build Coastguard Worker  * @arg latency		Latency in micro seconds.
210*4dc78e53SAndroid Build Coastguard Worker  *
211*4dc78e53SAndroid Build Coastguard Worker  * Calculates and sets the limit based on the desired latency and the
212*4dc78e53SAndroid Build Coastguard Worker  * configured rate and peak rate. In order for this operation to succeed,
213*4dc78e53SAndroid Build Coastguard Worker  * the rate and if required the peak rate must have been set in advance.
214*4dc78e53SAndroid Build Coastguard Worker  *
215*4dc78e53SAndroid Build Coastguard Worker  * @f[
216*4dc78e53SAndroid Build Coastguard Worker  *   limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n
217*4dc78e53SAndroid Build Coastguard Worker  * @f]
218*4dc78e53SAndroid Build Coastguard Worker  * @f[
219*4dc78e53SAndroid Build Coastguard Worker  *   limit = min(limit_{rate},limit_{peak})
220*4dc78e53SAndroid Build Coastguard Worker  * @f]
221*4dc78e53SAndroid Build Coastguard Worker  *
222*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
223*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc * qdisc,int latency)224*4dc78e53SAndroid Build Coastguard Worker int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency)
225*4dc78e53SAndroid Build Coastguard Worker {
226*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf;
227*4dc78e53SAndroid Build Coastguard Worker 	double limit, limit2;
228*4dc78e53SAndroid Build Coastguard Worker 
229*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
230*4dc78e53SAndroid Build Coastguard Worker 		BUG();
231*4dc78e53SAndroid Build Coastguard Worker 
232*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf->qt_mask & TBF_ATTR_RATE))
233*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MISSING_ATTR;
234*4dc78e53SAndroid Build Coastguard Worker 
235*4dc78e53SAndroid Build Coastguard Worker 	limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket);
236*4dc78e53SAndroid Build Coastguard Worker 
237*4dc78e53SAndroid Build Coastguard Worker 	if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
238*4dc78e53SAndroid Build Coastguard Worker 		limit2 = calc_limit(&tbf->qt_peakrate, latency,
239*4dc78e53SAndroid Build Coastguard Worker 				    tbf->qt_peakrate_bucket);
240*4dc78e53SAndroid Build Coastguard Worker 
241*4dc78e53SAndroid Build Coastguard Worker 		if (limit2 < limit)
242*4dc78e53SAndroid Build Coastguard Worker 			limit = limit2;
243*4dc78e53SAndroid Build Coastguard Worker 	}
244*4dc78e53SAndroid Build Coastguard Worker 
245*4dc78e53SAndroid Build Coastguard Worker 	rtnl_qdisc_tbf_set_limit(qdisc, (int) limit);
246*4dc78e53SAndroid Build Coastguard Worker 
247*4dc78e53SAndroid Build Coastguard Worker 	return 0;
248*4dc78e53SAndroid Build Coastguard Worker }
249*4dc78e53SAndroid Build Coastguard Worker 
250*4dc78e53SAndroid Build Coastguard Worker /**
251*4dc78e53SAndroid Build Coastguard Worker  * Get limit of TBF qdisc.
252*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		TBF qdisc.
253*4dc78e53SAndroid Build Coastguard Worker  * @return Limit in bytes or a negative error code.
254*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc * qdisc)255*4dc78e53SAndroid Build Coastguard Worker int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc)
256*4dc78e53SAndroid Build Coastguard Worker {
257*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf;
258*4dc78e53SAndroid Build Coastguard Worker 
259*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
260*4dc78e53SAndroid Build Coastguard Worker 		BUG();
261*4dc78e53SAndroid Build Coastguard Worker 
262*4dc78e53SAndroid Build Coastguard Worker 	if (tbf->qt_mask & TBF_ATTR_LIMIT)
263*4dc78e53SAndroid Build Coastguard Worker 		return tbf->qt_limit;
264*4dc78e53SAndroid Build Coastguard Worker 	else
265*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
266*4dc78e53SAndroid Build Coastguard Worker }
267*4dc78e53SAndroid Build Coastguard Worker 
calc_cell_log(int cell,int bucket)268*4dc78e53SAndroid Build Coastguard Worker static inline int calc_cell_log(int cell, int bucket)
269*4dc78e53SAndroid Build Coastguard Worker {
270*4dc78e53SAndroid Build Coastguard Worker 		cell = rtnl_tc_calc_cell_log(cell);
271*4dc78e53SAndroid Build Coastguard Worker 	return cell;
272*4dc78e53SAndroid Build Coastguard Worker }
273*4dc78e53SAndroid Build Coastguard Worker 
274*4dc78e53SAndroid Build Coastguard Worker /**
275*4dc78e53SAndroid Build Coastguard Worker  * Set rate of TBF qdisc.
276*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		TBF qdisc to be modified.
277*4dc78e53SAndroid Build Coastguard Worker  * @arg rate		New rate in bytes per second.
278*4dc78e53SAndroid Build Coastguard Worker  * @arg bucket		Size of bucket in bytes.
279*4dc78e53SAndroid Build Coastguard Worker  * @arg cell		Size of a rate cell or 0 to get default value.
280*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
281*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc * qdisc,int rate,int bucket,int cell)282*4dc78e53SAndroid Build Coastguard Worker void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
283*4dc78e53SAndroid Build Coastguard Worker 			    int cell)
284*4dc78e53SAndroid Build Coastguard Worker {
285*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf;
286*4dc78e53SAndroid Build Coastguard Worker 	int cell_log;
287*4dc78e53SAndroid Build Coastguard Worker 
288*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
289*4dc78e53SAndroid Build Coastguard Worker 		BUG();
290*4dc78e53SAndroid Build Coastguard Worker 
291*4dc78e53SAndroid Build Coastguard Worker 	if (!cell)
292*4dc78e53SAndroid Build Coastguard Worker 		cell_log = UINT8_MAX;
293*4dc78e53SAndroid Build Coastguard Worker 	else
294*4dc78e53SAndroid Build Coastguard Worker 		cell_log = rtnl_tc_calc_cell_log(cell);
295*4dc78e53SAndroid Build Coastguard Worker 
296*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_rate.rs_rate64 = (uint32_t)rate;
297*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_rate_bucket = bucket;
298*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_rate.rs_cell_log = cell_log;
299*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_rate_txtime = nl_us2ticks(rtnl_tc_calc_txtime64(bucket, tbf->qt_rate.rs_rate64));
300*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_mask |= TBF_ATTR_RATE;
301*4dc78e53SAndroid Build Coastguard Worker }
302*4dc78e53SAndroid Build Coastguard Worker 
303*4dc78e53SAndroid Build Coastguard Worker /**
304*4dc78e53SAndroid Build Coastguard Worker  * Get rate of TBF qdisc.
305*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		TBF qdisc.
306*4dc78e53SAndroid Build Coastguard Worker  * @return Rate in bytes per seconds or a negative error code.
307*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc * qdisc)308*4dc78e53SAndroid Build Coastguard Worker int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc)
309*4dc78e53SAndroid Build Coastguard Worker {
310*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf;
311*4dc78e53SAndroid Build Coastguard Worker 
312*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
313*4dc78e53SAndroid Build Coastguard Worker 		BUG();
314*4dc78e53SAndroid Build Coastguard Worker 
315*4dc78e53SAndroid Build Coastguard Worker 	if (tbf->qt_mask & TBF_ATTR_RATE)
316*4dc78e53SAndroid Build Coastguard Worker 		return tbf->qt_rate.rs_rate64;
317*4dc78e53SAndroid Build Coastguard Worker 	else
318*4dc78e53SAndroid Build Coastguard Worker 		return -1;
319*4dc78e53SAndroid Build Coastguard Worker }
320*4dc78e53SAndroid Build Coastguard Worker 
321*4dc78e53SAndroid Build Coastguard Worker /**
322*4dc78e53SAndroid Build Coastguard Worker  * Get rate bucket size of TBF qdisc.
323*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		TBF qdisc.
324*4dc78e53SAndroid Build Coastguard Worker  * @return Size of rate bucket or a negative error code.
325*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc * qdisc)326*4dc78e53SAndroid Build Coastguard Worker int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc)
327*4dc78e53SAndroid Build Coastguard Worker {
328*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf;
329*4dc78e53SAndroid Build Coastguard Worker 
330*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
331*4dc78e53SAndroid Build Coastguard Worker 		BUG();
332*4dc78e53SAndroid Build Coastguard Worker 
333*4dc78e53SAndroid Build Coastguard Worker 	if (tbf->qt_mask & TBF_ATTR_RATE)
334*4dc78e53SAndroid Build Coastguard Worker 		return tbf->qt_rate_bucket;
335*4dc78e53SAndroid Build Coastguard Worker 	else
336*4dc78e53SAndroid Build Coastguard Worker 		return -1;
337*4dc78e53SAndroid Build Coastguard Worker }
338*4dc78e53SAndroid Build Coastguard Worker 
339*4dc78e53SAndroid Build Coastguard Worker /**
340*4dc78e53SAndroid Build Coastguard Worker  * Get rate cell size of TBF qdisc.
341*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		TBF qdisc.
342*4dc78e53SAndroid Build Coastguard Worker  * @return Size of rate cell in bytes or a negative error code.
343*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc * qdisc)344*4dc78e53SAndroid Build Coastguard Worker int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc)
345*4dc78e53SAndroid Build Coastguard Worker {
346*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf;
347*4dc78e53SAndroid Build Coastguard Worker 
348*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
349*4dc78e53SAndroid Build Coastguard Worker 		BUG();
350*4dc78e53SAndroid Build Coastguard Worker 
351*4dc78e53SAndroid Build Coastguard Worker 	if (tbf->qt_mask & TBF_ATTR_RATE)
352*4dc78e53SAndroid Build Coastguard Worker 		return (1 << tbf->qt_rate.rs_cell_log);
353*4dc78e53SAndroid Build Coastguard Worker 	else
354*4dc78e53SAndroid Build Coastguard Worker 		return -1;
355*4dc78e53SAndroid Build Coastguard Worker }
356*4dc78e53SAndroid Build Coastguard Worker 
357*4dc78e53SAndroid Build Coastguard Worker /**
358*4dc78e53SAndroid Build Coastguard Worker  * Set peak rate of TBF qdisc.
359*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		TBF qdisc to be modified.
360*4dc78e53SAndroid Build Coastguard Worker  * @arg rate		New peak rate in bytes per second.
361*4dc78e53SAndroid Build Coastguard Worker  * @arg bucket		Size of peakrate bucket.
362*4dc78e53SAndroid Build Coastguard Worker  * @arg cell		Size of a peakrate cell or 0 to get default value.
363*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
364*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc * qdisc,int rate,int bucket,int cell)365*4dc78e53SAndroid Build Coastguard Worker int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
366*4dc78e53SAndroid Build Coastguard Worker 				int cell)
367*4dc78e53SAndroid Build Coastguard Worker {
368*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf;
369*4dc78e53SAndroid Build Coastguard Worker 	int cell_log;
370*4dc78e53SAndroid Build Coastguard Worker 
371*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
372*4dc78e53SAndroid Build Coastguard Worker 		BUG();
373*4dc78e53SAndroid Build Coastguard Worker 
374*4dc78e53SAndroid Build Coastguard Worker 	cell_log = calc_cell_log(cell, bucket);
375*4dc78e53SAndroid Build Coastguard Worker 	if (cell_log < 0)
376*4dc78e53SAndroid Build Coastguard Worker 		return cell_log;
377*4dc78e53SAndroid Build Coastguard Worker 
378*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_peakrate.rs_rate64 = (uint32_t)rate;
379*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_peakrate_bucket = bucket;
380*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_peakrate.rs_cell_log = cell_log;
381*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_peakrate_txtime = nl_us2ticks(rtnl_tc_calc_txtime64(bucket, tbf->qt_peakrate.rs_rate64));
382*4dc78e53SAndroid Build Coastguard Worker 
383*4dc78e53SAndroid Build Coastguard Worker 	tbf->qt_mask |= TBF_ATTR_PEAKRATE;
384*4dc78e53SAndroid Build Coastguard Worker 
385*4dc78e53SAndroid Build Coastguard Worker 	return 0;
386*4dc78e53SAndroid Build Coastguard Worker }
387*4dc78e53SAndroid Build Coastguard Worker 
388*4dc78e53SAndroid Build Coastguard Worker /**
389*4dc78e53SAndroid Build Coastguard Worker  * Get peak rate of TBF qdisc.
390*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		TBF qdisc.
391*4dc78e53SAndroid Build Coastguard Worker  * @return Peak rate in bytes per seconds or a negative error code.
392*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc * qdisc)393*4dc78e53SAndroid Build Coastguard Worker int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc)
394*4dc78e53SAndroid Build Coastguard Worker {
395*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf;
396*4dc78e53SAndroid Build Coastguard Worker 
397*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
398*4dc78e53SAndroid Build Coastguard Worker 		BUG();
399*4dc78e53SAndroid Build Coastguard Worker 
400*4dc78e53SAndroid Build Coastguard Worker 	if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
401*4dc78e53SAndroid Build Coastguard Worker 		return tbf->qt_peakrate.rs_rate64;
402*4dc78e53SAndroid Build Coastguard Worker 	else
403*4dc78e53SAndroid Build Coastguard Worker 		return -1;
404*4dc78e53SAndroid Build Coastguard Worker }
405*4dc78e53SAndroid Build Coastguard Worker 
406*4dc78e53SAndroid Build Coastguard Worker /**
407*4dc78e53SAndroid Build Coastguard Worker  * Get peak rate bucket size of TBF qdisc.
408*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		TBF qdisc.
409*4dc78e53SAndroid Build Coastguard Worker  * @return Size of peak rate bucket or a negative error code.
410*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc * qdisc)411*4dc78e53SAndroid Build Coastguard Worker int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc)
412*4dc78e53SAndroid Build Coastguard Worker {
413*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf;
414*4dc78e53SAndroid Build Coastguard Worker 
415*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
416*4dc78e53SAndroid Build Coastguard Worker 		BUG();
417*4dc78e53SAndroid Build Coastguard Worker 
418*4dc78e53SAndroid Build Coastguard Worker 	if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
419*4dc78e53SAndroid Build Coastguard Worker 		return tbf->qt_peakrate_bucket;
420*4dc78e53SAndroid Build Coastguard Worker 	else
421*4dc78e53SAndroid Build Coastguard Worker 		return -1;
422*4dc78e53SAndroid Build Coastguard Worker }
423*4dc78e53SAndroid Build Coastguard Worker 
424*4dc78e53SAndroid Build Coastguard Worker /**
425*4dc78e53SAndroid Build Coastguard Worker  * Get peak rate cell size of TBF qdisc.
426*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		TBF qdisc.
427*4dc78e53SAndroid Build Coastguard Worker  * @return Size of peak rate cell in bytes or a negative error code.
428*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc * qdisc)429*4dc78e53SAndroid Build Coastguard Worker int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc)
430*4dc78e53SAndroid Build Coastguard Worker {
431*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_tbf *tbf;
432*4dc78e53SAndroid Build Coastguard Worker 
433*4dc78e53SAndroid Build Coastguard Worker 	if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
434*4dc78e53SAndroid Build Coastguard Worker 		BUG();
435*4dc78e53SAndroid Build Coastguard Worker 
436*4dc78e53SAndroid Build Coastguard Worker 	if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
437*4dc78e53SAndroid Build Coastguard Worker 		return (1 << tbf->qt_peakrate.rs_cell_log);
438*4dc78e53SAndroid Build Coastguard Worker 	else
439*4dc78e53SAndroid Build Coastguard Worker 		return -1;
440*4dc78e53SAndroid Build Coastguard Worker }
441*4dc78e53SAndroid Build Coastguard Worker 
442*4dc78e53SAndroid Build Coastguard Worker /** @} */
443*4dc78e53SAndroid Build Coastguard Worker 
444*4dc78e53SAndroid Build Coastguard Worker static struct rtnl_tc_ops tbf_tc_ops = {
445*4dc78e53SAndroid Build Coastguard Worker 	.to_kind		= "tbf",
446*4dc78e53SAndroid Build Coastguard Worker 	.to_type		= RTNL_TC_TYPE_QDISC,
447*4dc78e53SAndroid Build Coastguard Worker 	.to_size		= sizeof(struct rtnl_tbf),
448*4dc78e53SAndroid Build Coastguard Worker 	.to_msg_parser		= tbf_msg_parser,
449*4dc78e53SAndroid Build Coastguard Worker 	.to_dump = {
450*4dc78e53SAndroid Build Coastguard Worker 	    [NL_DUMP_LINE]	= tbf_dump_line,
451*4dc78e53SAndroid Build Coastguard Worker 	    [NL_DUMP_DETAILS]	= tbf_dump_details,
452*4dc78e53SAndroid Build Coastguard Worker 	},
453*4dc78e53SAndroid Build Coastguard Worker 	.to_msg_fill		= tbf_msg_fill,
454*4dc78e53SAndroid Build Coastguard Worker };
455*4dc78e53SAndroid Build Coastguard Worker 
tbf_init(void)456*4dc78e53SAndroid Build Coastguard Worker static void _nl_init tbf_init(void)
457*4dc78e53SAndroid Build Coastguard Worker {
458*4dc78e53SAndroid Build Coastguard Worker 	rtnl_tc_register(&tbf_tc_ops);
459*4dc78e53SAndroid Build Coastguard Worker }
460*4dc78e53SAndroid Build Coastguard Worker 
tbf_exit(void)461*4dc78e53SAndroid Build Coastguard Worker static void _nl_exit tbf_exit(void)
462*4dc78e53SAndroid Build Coastguard Worker {
463*4dc78e53SAndroid Build Coastguard Worker 	rtnl_tc_unregister(&tbf_tc_ops);
464*4dc78e53SAndroid Build Coastguard Worker }
465*4dc78e53SAndroid Build Coastguard Worker 
466*4dc78e53SAndroid Build Coastguard Worker /** @} */
467