libnl 1.1.4
tbf.c
1/*
2 * lib/route/sch/tbf.c TBF Qdisc
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation version 2.1
7 * of the License.
8 *
9 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
10 */
11
12/**
13 * @ingroup qdisc_api
14 * @defgroup tbf Token Bucket Filter (TBF)
15 * @{
16 */
17
18#include <netlink-local.h>
19#include <netlink-tc.h>
20#include <netlink/netlink.h>
21#include <netlink/cache.h>
22#include <netlink/utils.h>
23#include <netlink/route/tc.h>
24#include <netlink/route/qdisc.h>
25#include <netlink/route/qdisc-modules.h>
26#include <netlink/route/class.h>
27#include <netlink/route/class-modules.h>
28#include <netlink/route/link.h>
29#include <netlink/route/sch/tbf.h>
30
31/** @cond SKIP */
32#define TBF_ATTR_LIMIT 0x01
33#define TBF_ATTR_RATE 0x02
34#define TBF_ATTR_PEAKRATE 0x10
35#define TBF_ATTR_MPU 0x80
36/** @endcond */
37
38static inline struct rtnl_tbf *tbf_qdisc(struct rtnl_qdisc *qdisc)
39{
40 return (struct rtnl_tbf *) qdisc->q_subdata;
41}
42
43static inline struct rtnl_tbf *tbf_alloc(struct rtnl_qdisc *qdisc)
44{
45 if (!qdisc->q_subdata)
46 qdisc->q_subdata = calloc(1, sizeof(struct rtnl_tbf));
47
48 return tbf_qdisc(qdisc);
49}
50
51static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = {
52 [TCA_TBF_PARMS] = { .minlen = sizeof(struct tc_tbf_qopt) },
53};
54
55static int tbf_msg_parser(struct rtnl_qdisc *q)
56{
57 int err;
58 struct nlattr *tb[TCA_TBF_MAX + 1];
59 struct rtnl_tbf *tbf;
60
61 err = tca_parse(tb, TCA_TBF_MAX, (struct rtnl_tca *) q, tbf_policy);
62 if (err < 0)
63 return err;
64
65 tbf = tbf_qdisc(q);
66 if (!tbf)
67 return nl_errno(ENOMEM);
68
69 if (tb[TCA_TBF_PARMS]) {
70 struct tc_tbf_qopt opts;
71 int bufsize;
72
73 nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts));
74 tbf->qt_limit = opts.limit;
75 tbf->qt_mpu = opts.rate.mpu;
76
77 rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate);
78 tbf->qt_rate_txtime = opts.buffer;
79 bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
80 opts.rate.rate);
81 tbf->qt_rate_bucket = bufsize;
82
83 rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate);
84 tbf->qt_peakrate_txtime = opts.mtu;
85 bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu),
86 opts.peakrate.rate);
87 tbf->qt_peakrate_bucket = bufsize;
88
89 tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_MPU | TBF_ATTR_RATE |
90 TBF_ATTR_PEAKRATE);
91 }
92
93 return 0;
94}
95
96static int tbf_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
97 int line)
98{
99 double r, rbit, lim;
100 char *ru, *rubit, *limu;
101 struct rtnl_tbf *tbf = tbf_qdisc(qdisc);
102
103 if (!tbf)
104 goto ignore;
105
106 r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru);
107 rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit);
108 lim = nl_cancel_down_bytes(tbf->qt_limit, &limu);
109
110 dp_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s",
111 r, ru, rbit, rubit, lim, limu);
112
113ignore:
114 return line;
115}
116
117static int tbf_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
118 int line)
119{
120 struct rtnl_tbf *tbf = tbf_qdisc(qdisc);
121
122 if (!tbf)
123 goto ignore;
124
125 if (1) {
126 char *bu, *cu;
127 double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu);
128 double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log,
129 &cu);
130
131 dp_dump(p, "mpu %u rate-bucket-size %1.f%s "
132 "rate-cell-size %.1f%s\n",
133 tbf->qt_mpu, bs, bu, cl, cu);
134
135 }
136
137 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
138 char *pru, *prbu, *bsu, *clu;
139 double pr, prb, bs, cl;
140
141 pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru);
142 prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu);
143 bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu);
144 cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log,
145 &clu);
146
147 dp_dump_line(p, line++, " peak-rate %.2f%s/s (%.0f%s) "
148 "bucket-size %.1f%s cell-size %.1f%s",
149 "latency %.1f%s",
150 pr, pru, prb, prbu, bs, bsu, cl, clu);
151 }
152
153ignore:
154 return line;
155}
156
157static struct nl_msg *tbf_get_opts(struct rtnl_qdisc *qdisc)
158{
159 struct tc_tbf_qopt opts;
160 struct rtnl_tbf *tbf;
161 struct nl_msg *msg;
162 uint32_t rtab[RTNL_TC_RTABLE_SIZE];
163 uint32_t ptab[RTNL_TC_RTABLE_SIZE];
164 int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
165
166 memset(&opts, 0, sizeof(opts));
167
168 tbf = tbf_qdisc(qdisc);
169 if (!tbf)
170 return NULL;
171
172 if (!(tbf->qt_mask & required) != required)
173 return NULL;
174
175 opts.limit = tbf->qt_limit;
176 opts.buffer = tbf->qt_rate_txtime;
177 tbf->qt_rate.rs_mpu = tbf->qt_mpu;
178 rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate);
179
180 rtnl_tc_build_rate_table(rtab, tbf->qt_mpu & 0xff, tbf->qt_mpu >> 8,
181 1 << tbf->qt_rate.rs_cell_log,
182 tbf->qt_rate.rs_rate);
183
184 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
185 opts.mtu = tbf->qt_peakrate_txtime;
186 tbf->qt_peakrate.rs_mpu = tbf->qt_mpu;
187 rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate);
188
189 rtnl_tc_build_rate_table(ptab, tbf->qt_mpu & 0xff,
190 tbf->qt_mpu >> 8,
191 1 << tbf->qt_peakrate.rs_cell_log,
192 tbf->qt_peakrate.rs_rate);
193 }
194
195 msg = nlmsg_alloc();
196 if (!msg)
197 goto nla_put_failure;
198
199 NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opts), &opts);
200 NLA_PUT(msg, TCA_TBF_RTAB, sizeof(rtab), rtab);
201
202 if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
203 NLA_PUT(msg, TCA_TBF_PTAB, sizeof(ptab), ptab);
204
205 return msg;
206
207nla_put_failure:
208 nlmsg_free(msg);
209 return NULL;
210}
211
212/**
213 * @name Attribute Access
214 * @{
215 */
216
217/**
218 * Set limit of TBF qdisc.
219 * @arg qdisc TBF qdisc to be modified.
220 * @arg limit New limit in bytes.
221 * @return 0 on success or a negative error code.
222 */
223int rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit)
224{
225 struct rtnl_tbf *tbf;
226
227 tbf = tbf_alloc(qdisc);
228 if (!tbf)
229 return nl_errno(ENOMEM);
230
231 tbf->qt_limit = limit;
232 tbf->qt_mask |= TBF_ATTR_LIMIT;
233
234 return 0;
235}
236
237static inline double calc_limit(struct rtnl_ratespec *spec, int latency,
238 int bucket)
239{
240 double limit;
241
242 limit = (double) spec->rs_rate * ((double) latency / 1000000.);
243 limit += bucket;
244
245 return limit;
246}
247
248/**
249 * Set limit of TBF qdisc by latency.
250 * @arg qdisc TBF qdisc to be modified.
251 * @arg latency Latency in micro seconds.
252 *
253 * Calculates and sets the limit based on the desired latency and the
254 * configured rate and peak rate. In order for this operation to succeed,
255 * the rate and if required the peak rate must have been set in advance.
256 *
257 * @f[
258 * limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n
259 * @f]
260 * @f[
261 * limit = min(limit_{rate},limit_{peak})
262 * @f]
263 *
264 * @return 0 on success or a negative error code.
265 */
266int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency)
267{
268 struct rtnl_tbf *tbf;
269 double limit, limit2;
270
271 tbf = tbf_alloc(qdisc);
272 if (!tbf)
273 return nl_errno(ENOMEM);
274
275 if (!(tbf->qt_mask & TBF_ATTR_RATE))
276 return nl_error(EINVAL, "The rate must be specified before "
277 "limit can be calculated based on latency.");
278
279 limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket);
280
281 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
282 limit2 = calc_limit(&tbf->qt_peakrate, latency,
283 tbf->qt_peakrate_bucket);
284
285 if (limit2 < limit)
286 limit = limit2;
287 }
288
289 return rtnl_qdisc_tbf_set_limit(qdisc, (int) limit);
290}
291
292/**
293 * Get limit of TBF qdisc.
294 * @arg qdisc TBF qdisc.
295 * @return Limit in bytes or a negative error code.
296 */
297int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc)
298{
299 struct rtnl_tbf *tbf;
300
301 tbf = tbf_qdisc(qdisc);
302 if (tbf && (tbf->qt_mask & TBF_ATTR_LIMIT))
303 return tbf->qt_limit;
304 return
305 nl_errno(ENOENT);
306}
307
308/**
309 * Set MPU of TBF qdisc.
310 * @arg qdisc TBF qdisc to be modified.
311 * @arg mpu New MPU in bytes.
312 * @return 0 on success or a negative error code.
313 */
314int rtnl_qdisc_tbf_set_mpu(struct rtnl_qdisc *qdisc, int mpu)
315{
316 struct rtnl_tbf *tbf;
317
318 tbf = tbf_alloc(qdisc);
319 if (!tbf)
320 return nl_errno(ENOMEM);
321
322 tbf->qt_mpu = mpu;
323 tbf->qt_mask |= TBF_ATTR_MPU;
324
325 return 0;
326}
327
328/**
329 * Get MPU of TBF qdisc.
330 * @arg qdisc TBF qdisc.
331 * @return MPU in bytes or a negative error code.
332 */
333int rtnl_qdisc_tbf_get_mpu(struct rtnl_qdisc *qdisc)
334{
335 struct rtnl_tbf *tbf;
336
337 tbf = tbf_qdisc(qdisc);
338 if (tbf && (tbf->qt_mask & TBF_ATTR_MPU))
339 return tbf->qt_mpu;
340 return
341 nl_errno(ENOENT);
342}
343
344static inline int calc_cell_log(int cell, int bucket)
345{
346 if (cell > 0)
347 cell = rtnl_tc_calc_cell_log(cell);
348 else {
349 cell = 0;
350
351 if (!bucket)
352 bucket = 2047; /* defaults to cell_log=3 */
353
354 while ((bucket >> cell) > 255)
355 cell++;
356 }
357
358 return cell;
359}
360
361/**
362 * Set rate of TBF qdisc.
363 * @arg qdisc TBF qdisc to be modified.
364 * @arg rate New rate in bytes per second.
365 * @arg bucket Size of bucket in bytes.
366 * @arg cell Size of a rate cell or 0 to get default value.
367 * @return 0 on success or a negative error code.
368 */
369int rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
370 int cell)
371{
372 struct rtnl_tbf *tbf;
373 int cell_log;
374
375 tbf = tbf_alloc(qdisc);
376 if (!tbf)
377 return nl_errno(ENOMEM);
378
379 cell_log = calc_cell_log(cell, bucket);
380 if (cell_log < 0)
381 return cell_log;
382
383 tbf->qt_rate.rs_rate = rate;
384 tbf->qt_rate_bucket = bucket;
385 tbf->qt_rate.rs_cell_log = cell_log;
386 tbf->qt_rate_txtime = rtnl_tc_calc_txtime(bucket, rate);
387 tbf->qt_mask |= TBF_ATTR_RATE;
388
389 return 0;
390}
391
392/**
393 * Get rate of TBF qdisc.
394 * @arg qdisc TBF qdisc.
395 * @return Rate in bytes per seconds or a negative error code.
396 */
397int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc)
398{
399 struct rtnl_tbf *tbf;
400
401 tbf = tbf_qdisc(qdisc);
402 if (tbf && (tbf->qt_mask & TBF_ATTR_RATE))
403 return tbf->qt_rate.rs_rate;
404 else
405 return -1;
406}
407
408/**
409 * Get rate bucket size of TBF qdisc.
410 * @arg qdisc TBF qdisc.
411 * @return Size of rate bucket or a negative error code.
412 */
413int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc)
414{
415 struct rtnl_tbf *tbf;
416
417 tbf = tbf_qdisc(qdisc);
418 if (tbf && (tbf->qt_mask & TBF_ATTR_RATE))
419 return tbf->qt_rate_bucket;
420 else
421 return -1;
422}
423
424/**
425 * Get rate cell size of TBF qdisc.
426 * @arg qdisc TBF qdisc.
427 * @return Size of rate cell in bytes or a negative error code.
428 */
429int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc)
430{
431 struct rtnl_tbf *tbf;
432
433 tbf = tbf_qdisc(qdisc);
434 if (tbf && (tbf->qt_mask & TBF_ATTR_RATE))
435 return (1 << tbf->qt_rate.rs_cell_log);
436 else
437 return -1;
438}
439
440/**
441 * Set peak rate of TBF qdisc.
442 * @arg qdisc TBF qdisc to be modified.
443 * @arg rate New peak rate in bytes per second.
444 * @arg bucket Size of peakrate bucket.
445 * @arg cell Size of a peakrate cell or 0 to get default value.
446 * @return 0 on success or a negative error code.
447 */
448int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
449 int cell)
450{
451 struct rtnl_tbf *tbf;
452 int cell_log;
453
454 tbf = tbf_alloc(qdisc);
455 if (!tbf)
456 return nl_errno(ENOMEM);
457
458 cell_log = calc_cell_log(cell, bucket);
459 if (cell_log < 0)
460 return cell_log;
461
462 tbf->qt_peakrate.rs_rate = rate;
463 tbf->qt_peakrate_bucket = bucket;
464 tbf->qt_peakrate.rs_cell_log = cell_log;
465 tbf->qt_peakrate_txtime = rtnl_tc_calc_txtime(bucket, rate);
466
467 tbf->qt_mask |= TBF_ATTR_PEAKRATE;
468
469 return 0;
470}
471
472/**
473 * Get peak rate of TBF qdisc.
474 * @arg qdisc TBF qdisc.
475 * @return Peak rate in bytes per seconds or a negative error code.
476 */
477int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc)
478{
479 struct rtnl_tbf *tbf;
480
481 tbf = tbf_qdisc(qdisc);
482 if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE))
483 return tbf->qt_peakrate.rs_rate;
484 else
485 return -1;
486}
487
488/**
489 * Get peak rate bucket size of TBF qdisc.
490 * @arg qdisc TBF qdisc.
491 * @return Size of peak rate bucket or a negative error code.
492 */
493int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc)
494{
495 struct rtnl_tbf *tbf;
496
497 tbf = tbf_qdisc(qdisc);
498 if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE))
499 return tbf->qt_peakrate_bucket;
500 else
501 return -1;
502}
503
504/**
505 * Get peak rate cell size of TBF qdisc.
506 * @arg qdisc TBF qdisc.
507 * @return Size of peak rate cell in bytes or a negative error code.
508 */
509int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc)
510{
511 struct rtnl_tbf *tbf;
512
513 tbf = tbf_qdisc(qdisc);
514 if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE))
515 return (1 << tbf->qt_peakrate.rs_cell_log);
516 else
517 return -1;
518}
519
520/** @} */
521
522static struct rtnl_qdisc_ops tbf_qdisc_ops = {
523 .qo_kind = "tbf",
524 .qo_msg_parser = tbf_msg_parser,
525 .qo_dump[NL_DUMP_BRIEF] = tbf_dump_brief,
526 .qo_dump[NL_DUMP_FULL] = tbf_dump_full,
527 .qo_get_opts = tbf_get_opts,
528};
529
530static void __init tbf_init(void)
531{
532 rtnl_qdisc_register(&tbf_qdisc_ops);
533}
534
535static void __exit tbf_exit(void)
536{
537 rtnl_qdisc_unregister(&tbf_qdisc_ops);
538}
539
540/** @} */
#define NLA_PUT(n, attrtype, attrlen, data)
Add a netlink attribute to a netlink message.
Definition: attr.h:157
int nla_memcpy(void *dest, struct nlattr *src, int count)
Copy a netlink attribute into another memory area.
Definition: attr.c:382
void nlmsg_free(struct nl_msg *n)
Free a netlink message.
Definition: msg.c:656
struct nl_msg * nlmsg_alloc(void)
Allocate a new netlink message with the default maximum payload size.
Definition: msg.c:401
int rtnl_qdisc_unregister(struct rtnl_qdisc_ops *qops)
Unregister a qdisc module.
Definition: qdisc_api.c:61
int rtnl_qdisc_register(struct rtnl_qdisc_ops *qops)
Register a qdisc module.
Definition: qdisc_api.c:40
int rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, int cell)
Set rate of TBF qdisc.
Definition: tbf.c:369
int rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit)
Set limit of TBF qdisc.
Definition: tbf.c:223
int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency)
Set limit of TBF qdisc by latency.
Definition: tbf.c:266
int rtnl_qdisc_tbf_set_mpu(struct rtnl_qdisc *qdisc, int mpu)
Set MPU of TBF qdisc.
Definition: tbf.c:314
int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc)
Get rate of TBF qdisc.
Definition: tbf.c:397
int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc)
Get peak rate bucket size of TBF qdisc.
Definition: tbf.c:493
int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc)
Get rate cell size of TBF qdisc.
Definition: tbf.c:429
int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc)
Get rate bucket size of TBF qdisc.
Definition: tbf.c:413
int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc)
Get limit of TBF qdisc.
Definition: tbf.c:297
int rtnl_qdisc_tbf_get_mpu(struct rtnl_qdisc *qdisc)
Get MPU of TBF qdisc.
Definition: tbf.c:333
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:448
int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc)
Get peak rate cell size of TBF qdisc.
Definition: tbf.c:509
int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc)
Get peak rate of TBF qdisc.
Definition: tbf.c:477
int rtnl_tc_calc_cell_log(int cell_size)
Calculate the binary logarithm for a specific cell size.
Definition: tc.c:420
int rtnl_tc_calc_bufsize(int txtime, int rate)
Calculate buffer size able to transmit in a specific time and rate.
Definition: tc.c:406
#define RTNL_TC_RTABLE_SIZE
Number of entries in a transmission time lookup table.
Definition: tc.h:50
int rtnl_tc_build_rate_table(uint32_t *dst, uint8_t mpu, uint8_t overhead, int cell, int rate)
Compute a transmission time lookup table.
Definition: tc.c:454
int rtnl_tc_calc_txtime(int bufsize, int rate)
Calculate time required to transmit buffer at a specific rate.
Definition: tc.c:383
double nl_cancel_down_bits(unsigned long long l, char **unit)
Cancel down a bit counter.
Definition: utils.c:220
double nl_cancel_down_bytes(unsigned long long l, char **unit)
Cancel down a byte counter.
Definition: utils.c:189
uint32_t nl_ticks2us(uint32_t ticks)
Convert ticks to micro seconds.
Definition: utils.c:450
@ NL_DUMP_FULL
Dump all attributes but no statistics.
Definition: types.h:23
@ NL_DUMP_BRIEF
Dump object in a brief one-liner.
Definition: types.h:22
Dumping parameters.
Definition: types.h:37
attribute validation policy
Definition: attr.h:73
uint16_t minlen
Minimal length of payload required to be available.
Definition: attr.h:78
Qdisc Operations.
Definition: qdisc-modules.h:26
char qo_kind[32]
Kind/Name of Qdisc.
Definition: qdisc-modules.h:30