libnl  3.6.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 
29 static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = {
30  [TCA_TBF_PARMS] = { .minlen = sizeof(struct tc_tbf_qopt) },
31 };
32 
33 static 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 
70 static 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 
88 static 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, " peak-rate %.2f%s/s (%.0f%s) "
119  "bucket-size %.1f%s cell-size %.1f%s"
120  "latency %.1f%s",
121  pr, pru, prb, prbu, bs, bsu, cl, clu);
122  }
123 }
124 
125 static 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 
157 nla_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  */
172 void 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 
183 static 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  */
212 int 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  */
243 int 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 
256 static 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  */
270 void 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  */
296 int 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  */
314 int 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  */
332 int 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  */
353 int 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  */
381 int 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  */
399 int 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  */
417 int 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 
432 static 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 
444 static void __init tbf_init(void)
445 {
446  rtnl_tc_register(&tbf_tc_ops);
447 }
448 
449 static 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
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1079
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
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
Definition: tc.c:1018
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
Definition: tc.c:1052
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