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