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