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