libnl: /data/src/libnl3/lib/route/qdisc/tbf.c Source File

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