1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2003-2011 Thomas Graf <[email protected]>
4 * Copyright (c) 2005-2006 Petr Gotthard <[email protected]>
5 * Copyright (c) 2005-2006 Siemens AG Oesterreich
6 */
7
8 /**
9 * @ingroup qdisc
10 * @ingroup class
11 * @defgroup qdisc_htb Hierachical Token Bucket (HTB)
12 * @{
13 */
14
15 #include "nl-default.h"
16
17 #include <netlink/netlink.h>
18 #include <netlink/cache.h>
19 #include <netlink/utils.h>
20 #include <netlink/route/qdisc.h>
21 #include <netlink/route/class.h>
22 #include <netlink/route/link.h>
23 #include <netlink/route/qdisc/htb.h>
24
25 #include "tc-api.h"
26
27 /** @cond SKIP */
28 struct rtnl_htb_qdisc {
29 uint32_t qh_rate2quantum;
30 uint32_t qh_defcls;
31 uint32_t qh_mask;
32 uint32_t qh_direct_pkts;
33 };
34
35 struct rtnl_htb_class {
36 uint32_t ch_prio;
37 struct rtnl_ratespec ch_rate;
38 struct rtnl_ratespec ch_ceil;
39 uint32_t ch_rbuffer;
40 uint32_t ch_cbuffer;
41 uint32_t ch_quantum;
42 uint32_t ch_mask;
43 uint32_t ch_level;
44 };
45
46 #define SCH_HTB_HAS_RATE2QUANTUM 0x01
47 #define SCH_HTB_HAS_DEFCLS 0x02
48
49 #define SCH_HTB_HAS_PRIO 0x001
50 #define SCH_HTB_HAS_RATE 0x002
51 #define SCH_HTB_HAS_CEIL 0x004
52 #define SCH_HTB_HAS_RBUFFER 0x008
53 #define SCH_HTB_HAS_CBUFFER 0x010
54 #define SCH_HTB_HAS_QUANTUM 0x020
55 #define SCH_HTB_HAS_LEVEL 0x040
56 /** @endcond */
57
58 static struct nla_policy htb_policy[TCA_HTB_MAX+1] = {
59 [TCA_HTB_INIT] = { .minlen = sizeof(struct tc_htb_glob) },
60 [TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) },
61 [TCA_HTB_RATE64] = { .minlen = sizeof(uint64_t) },
62 [TCA_HTB_CEIL64] = { .minlen = sizeof(uint64_t) },
63 };
64
htb_qdisc_msg_parser(struct rtnl_tc * tc,void * data)65 static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
66 {
67 struct nlattr *tb[TCA_HTB_MAX + 1];
68 struct rtnl_htb_qdisc *htb = data;
69 int err;
70
71 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
72 return err;
73
74 if (tb[TCA_HTB_INIT]) {
75 struct tc_htb_glob opts;
76
77 nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts));
78 htb->qh_rate2quantum = opts.rate2quantum;
79 htb->qh_defcls = opts.defcls;
80 htb->qh_direct_pkts = opts.direct_pkts;
81
82 htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS);
83 }
84
85 return 0;
86 }
87
htb_class_msg_parser(struct rtnl_tc * tc,void * data)88 static int htb_class_msg_parser(struct rtnl_tc *tc, void *data)
89 {
90 struct nlattr *tb[TCA_HTB_MAX + 1];
91 struct rtnl_htb_class *htb = data;
92 int err;
93
94 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
95 return err;
96
97 if (tb[TCA_HTB_PARMS]) {
98 struct tc_htb_opt opts;
99
100 nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts));
101 htb->ch_prio = opts.prio;
102 rtnl_copy_ratespec(&htb->ch_rate, &opts.rate);
103 rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil);
104
105 if (tb[TCA_HTB_RATE64])
106 nla_memcpy(&htb->ch_rate.rs_rate64, tb[TCA_HTB_RATE64], sizeof(uint64_t));
107 if (tb[TCA_HTB_CEIL64])
108 nla_memcpy(&htb->ch_ceil.rs_rate64, tb[TCA_HTB_CEIL64], sizeof(uint64_t));
109
110 htb->ch_rbuffer = rtnl_tc_calc_bufsize64(nl_ticks2us(opts.buffer),
111 htb->ch_rate.rs_rate64);
112 htb->ch_cbuffer = rtnl_tc_calc_bufsize64(nl_ticks2us(opts.cbuffer),
113 htb->ch_ceil.rs_rate64);
114 htb->ch_quantum = opts.quantum;
115 htb->ch_level = opts.level;
116
117 rtnl_tc_set_mpu(tc, htb->ch_rate.rs_mpu);
118 rtnl_tc_set_overhead(tc, htb->ch_rate.rs_overhead);
119
120 htb->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE |
121 SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER |
122 SCH_HTB_HAS_CBUFFER | SCH_HTB_HAS_QUANTUM |
123 SCH_HTB_HAS_LEVEL);
124 }
125
126 return 0;
127 }
128
htb_qdisc_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)129 static void htb_qdisc_dump_line(struct rtnl_tc *tc, void *data,
130 struct nl_dump_params *p)
131 {
132 struct rtnl_htb_qdisc *htb = data;
133
134 if (!htb)
135 return;
136
137 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
138 nl_dump(p, " r2q %u", htb->qh_rate2quantum);
139
140 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) {
141 char buf[64];
142 nl_dump(p, " default-class %s",
143 rtnl_tc_handle2str(htb->qh_defcls, buf, sizeof(buf)));
144 }
145 }
146
htb_class_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)147 static void htb_class_dump_line(struct rtnl_tc *tc, void *data,
148 struct nl_dump_params *p)
149 {
150 struct rtnl_htb_class *htb = data;
151
152 if (!htb)
153 return;
154
155 if (htb->ch_mask & SCH_HTB_HAS_RATE) {
156 double r, rbit;
157 char *ru, *rubit;
158
159 r = nl_cancel_down_bytes(htb->ch_rate.rs_rate64, &ru);
160 rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate64*8, &rubit);
161
162 nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u",
163 r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log);
164 }
165 }
166
htb_class_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)167 static void htb_class_dump_details(struct rtnl_tc *tc, void *data,
168 struct nl_dump_params *p)
169 {
170 struct rtnl_htb_class *htb = data;
171
172 if (!htb)
173 return;
174
175 /* line 1 */
176 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
177 double r, rbit;
178 char *ru, *rubit;
179
180 r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate64, &ru);
181 rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate64*8, &rubit);
182
183 nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u",
184 r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log);
185 }
186
187 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
188 nl_dump(p, " prio %u", htb->ch_prio);
189
190 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) {
191 double b;
192 char *bu;
193
194 b = nl_cancel_down_bytes(htb->ch_rbuffer, &bu);
195 nl_dump(p, " rbuffer %.2f%s", b, bu);
196 }
197
198 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) {
199 double b;
200 char *bu;
201
202 b = nl_cancel_down_bytes(htb->ch_cbuffer, &bu);
203 nl_dump(p, " cbuffer %.2f%s", b, bu);
204 }
205
206 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
207 nl_dump(p, " quantum %u", htb->ch_quantum);
208 }
209
htb_qdisc_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)210 static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data,
211 struct nl_msg *msg)
212 {
213 struct rtnl_htb_qdisc *htb = data;
214 struct tc_htb_glob opts = {
215 .version = TC_HTB_PROTOVER,
216 .rate2quantum = 10,
217 };
218
219 if (htb) {
220 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
221 opts.rate2quantum = htb->qh_rate2quantum;
222
223 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS)
224 opts.defcls = htb->qh_defcls;
225 }
226
227 return nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts);
228 }
229
htb_class_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)230 static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
231 struct nl_msg *msg)
232 {
233 struct rtnl_htb_class *htb = data;
234 uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE];
235 struct tc_htb_opt opts;
236 int buffer, cbuffer;
237 uint64_t rate64;
238 uint64_t ceil64;
239
240 if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE))
241 BUG();
242
243 memset(&opts, 0, sizeof(opts));
244
245 /* if not set, zero (0) is used as priority */
246 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
247 opts.prio = htb->ch_prio;
248
249 mtu = rtnl_tc_get_mtu(tc);
250
251 rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable);
252 rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate);
253 rate64 = htb->ch_rate.rs_rate64;
254
255 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
256 rtnl_tc_build_rate_table(tc, &htb->ch_ceil, ctable);
257 rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil);
258 ceil64 = htb->ch_ceil.rs_rate64;
259 } else {
260 /*
261 * If not set, configured rate is used as ceil, which implies
262 * no borrowing.
263 */
264 memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec));
265 ceil64 = rate64;
266 }
267
268 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
269 buffer = htb->ch_rbuffer;
270 else
271 buffer = rate64 / nl_get_psched_hz() + mtu; /* XXX */
272
273 opts.buffer = nl_us2ticks(rtnl_tc_calc_txtime64(buffer, rate64));
274
275 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
276 cbuffer = htb->ch_cbuffer;
277 else
278 cbuffer = ceil64 / nl_get_psched_hz() + mtu; /* XXX */
279
280 opts.cbuffer = nl_us2ticks(rtnl_tc_calc_txtime64(cbuffer, ceil64));
281
282 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
283 opts.quantum = htb->ch_quantum;
284
285 NLA_PUT(msg, TCA_HTB_PARMS, sizeof(opts), &opts);
286 if (rate64 > 0xFFFFFFFFull)
287 NLA_PUT(msg, TCA_HTB_RATE64, sizeof(uint64_t), &rate64);
288 if (ceil64 > 0xFFFFFFFFull)
289 NLA_PUT(msg, TCA_HTB_CEIL64, sizeof(uint64_t), &ceil64);
290 NLA_PUT(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable);
291 NLA_PUT(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable);
292
293 return 0;
294
295 nla_put_failure:
296 return -NLE_MSGSIZE;
297 }
298
299 static struct rtnl_tc_ops htb_qdisc_ops;
300 static struct rtnl_tc_ops htb_class_ops;
301
htb_qdisc_data(struct rtnl_qdisc * qdisc,int * err)302 static struct rtnl_htb_qdisc *htb_qdisc_data(struct rtnl_qdisc *qdisc, int *err)
303 {
304 return rtnl_tc_data_check(TC_CAST(qdisc), &htb_qdisc_ops, err);
305 }
306
htb_class_data(struct rtnl_class * class,int * err)307 static struct rtnl_htb_class *htb_class_data(struct rtnl_class *class, int *err)
308 {
309 return rtnl_tc_data_check(TC_CAST(class), &htb_class_ops, err);
310 }
311
312 /**
313 * @name Attribute Modifications
314 * @{
315 */
316
317 /**
318 * Return rate/quantum ratio of HTB qdisc
319 * @arg qdisc htb qdisc object
320 *
321 * @return rate/quantum ratio or 0 if unspecified
322 */
rtnl_htb_get_rate2quantum(struct rtnl_qdisc * qdisc)323 uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc)
324 {
325 struct rtnl_htb_qdisc *htb;
326
327 if ((htb = htb_qdisc_data(qdisc, NULL)) &&
328 (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM))
329 return htb->qh_rate2quantum;
330
331 return 0;
332 }
333
rtnl_htb_set_rate2quantum(struct rtnl_qdisc * qdisc,uint32_t rate2quantum)334 int rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum)
335 {
336 struct rtnl_htb_qdisc *htb;
337 int err;
338
339 if (!(htb = htb_qdisc_data(qdisc, &err)))
340 return err;
341
342 htb->qh_rate2quantum = rate2quantum;
343 htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM;
344
345 return 0;
346 }
347
348 /**
349 * Return default class of HTB qdisc
350 * @arg qdisc htb qdisc object
351 *
352 * Returns the classid of the class where all unclassified traffic
353 * goes to.
354 *
355 * @return classid or TC_H_UNSPEC if unspecified.
356 */
rtnl_htb_get_defcls(struct rtnl_qdisc * qdisc)357 uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc)
358 {
359 struct rtnl_htb_qdisc *htb;
360
361 if ((htb = htb_qdisc_data(qdisc, NULL)) &&
362 htb->qh_mask & SCH_HTB_HAS_DEFCLS)
363 return htb->qh_defcls;
364
365 return TC_H_UNSPEC;
366 }
367
368 /**
369 * Set default class of the htb qdisc to the specified value
370 * @arg qdisc qdisc to change
371 * @arg defcls new default class
372 */
rtnl_htb_set_defcls(struct rtnl_qdisc * qdisc,uint32_t defcls)373 int rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
374 {
375 struct rtnl_htb_qdisc *htb;
376 int err;
377
378 if (!(htb = htb_qdisc_data(qdisc, &err)))
379 return err;
380
381 htb->qh_defcls = defcls;
382 htb->qh_mask |= SCH_HTB_HAS_DEFCLS;
383
384 return 0;
385 }
386
rtnl_htb_get_prio(struct rtnl_class * class)387 uint32_t rtnl_htb_get_prio(struct rtnl_class *class)
388 {
389 struct rtnl_htb_class *htb;
390
391 if ((htb = htb_class_data(class, NULL)) &&
392 (htb->ch_mask & SCH_HTB_HAS_PRIO))
393 return htb->ch_prio;
394
395 return 0;
396 }
397
rtnl_htb_set_prio(struct rtnl_class * class,uint32_t prio)398 int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio)
399 {
400 struct rtnl_htb_class *htb;
401 int err;
402
403 if (!(htb = htb_class_data(class, &err)))
404 return err;
405
406 htb->ch_prio = prio;
407 htb->ch_mask |= SCH_HTB_HAS_PRIO;
408
409 return 0;
410 }
411
412 /**
413 * Return rate of HTB class
414 * @arg class htb class object
415 *
416 * @return Rate in bytes/s or 0 if unspecified. If the value
417 * cannot be represented as 32 bit integer, (1<<32) is returned.
418 * Use rtnl_htb_get_rate64() instead.
419 */
rtnl_htb_get_rate(struct rtnl_class * class)420 uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
421 {
422 struct rtnl_htb_class *htb;
423
424 if ( !(htb = htb_class_data(class, NULL))
425 || !(htb->ch_mask & SCH_HTB_HAS_RATE))
426 return 0;
427
428 if (htb->ch_rate.rs_rate64 > 0xFFFFFFFFull)
429 return 0xFFFFFFFFull;
430
431 return htb->ch_rate.rs_rate64;
432 }
433
434 /**
435 * Return rate of HTB class
436 * @arg class htb class object
437 * @arg out_rate64 on success, the set rate.
438 *
439 * @return 0 on success or a negative error code.
440 */
rtnl_htb_get_rate64(struct rtnl_class * class,uint64_t * out_rate64)441 int rtnl_htb_get_rate64(struct rtnl_class *class, uint64_t *out_rate64)
442 {
443 struct rtnl_htb_class *htb;
444
445 if (!(htb = htb_class_data(class, NULL)))
446 return -NLE_INVAL;
447 if (!(htb->ch_mask & SCH_HTB_HAS_RATE))
448 return -NLE_NOATTR;
449
450 *out_rate64 = htb->ch_rate.rs_rate64;
451 return 0;
452 }
453
454 /**
455 * Set rate of HTB class
456 * @arg class htb class object
457 * @arg rate new rate in bytes per second
458 *
459 * @return 0 on success or a negative error code.
460 */
rtnl_htb_set_rate(struct rtnl_class * class,uint32_t rate)461 int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
462 {
463 return rtnl_htb_set_rate64(class, rate);
464 }
465
466 /**
467 * Set rate of HTB class
468 * @arg class htb class object
469 * @arg rate new rate in bytes per second
470 *
471 * @return 0 on success or a negative error code.
472 */
rtnl_htb_set_rate64(struct rtnl_class * class,uint64_t rate)473 int rtnl_htb_set_rate64(struct rtnl_class *class, uint64_t rate)
474 {
475 struct rtnl_htb_class *htb;
476 int err;
477
478 if (!(htb = htb_class_data(class, &err)))
479 return err;
480
481 htb->ch_rate.rs_cell_log = UINT8_MAX; /* use default value */
482 htb->ch_rate.rs_rate64 = rate;
483 htb->ch_mask |= SCH_HTB_HAS_RATE;
484
485 return 0;
486 }
487
488 /**
489 * Return ceil rate of HTB class
490 * @arg class htb class object
491 *
492 * @return Ceil rate in bytes/s or 0 if unspecified. If the value
493 * cannot be represented as 32 bit integer, (1<<32) is returned.
494 * Use rtnl_htb_get_ceil64() instead.
495 */
rtnl_htb_get_ceil(struct rtnl_class * class)496 uint32_t rtnl_htb_get_ceil(struct rtnl_class *class)
497 {
498 struct rtnl_htb_class *htb;
499
500 if ( !(htb = htb_class_data(class, NULL))
501 || !(htb->ch_mask & SCH_HTB_HAS_CEIL))
502 return 0;
503
504 if (htb->ch_ceil.rs_rate64 > 0xFFFFFFFFull)
505 return 0xFFFFFFFFull;
506
507 return htb->ch_ceil.rs_rate64;
508 }
509
510 /**
511 * Return ceil rate of HTB class
512 * @arg class htb class object
513 * @arg out_ceil64 on success, the set ceil value.
514 *
515 * @return 0 on success or a negative error code.
516 */
rtnl_htb_get_ceil64(struct rtnl_class * class,uint64_t * out_ceil64)517 int rtnl_htb_get_ceil64(struct rtnl_class *class, uint64_t *out_ceil64)
518 {
519 struct rtnl_htb_class *htb;
520
521 if (!(htb = htb_class_data(class, NULL)))
522 return -NLE_INVAL;
523 if (!(htb->ch_mask & SCH_HTB_HAS_CEIL))
524 return -NLE_NOATTR;
525
526 *out_ceil64 = htb->ch_ceil.rs_rate64;
527 return 0;
528 }
529
530 /**
531 * Set ceil rate of HTB class
532 * @arg class htb class object
533 * @arg ceil new ceil rate number of bytes per second
534 *
535 * @return 0 on success or a negative error code.
536 */
rtnl_htb_set_ceil(struct rtnl_class * class,uint32_t ceil)537 int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
538 {
539 return rtnl_htb_set_ceil64(class, ceil);
540 }
541
542 /**
543 * Set ceil rate of HTB class
544 * @arg class htb class object
545 * @arg ceil64 new ceil rate number of bytes per second
546 *
547 * @return 0 on success or a negative error code.
548 */
rtnl_htb_set_ceil64(struct rtnl_class * class,uint64_t ceil64)549 int rtnl_htb_set_ceil64(struct rtnl_class *class, uint64_t ceil64)
550 {
551 struct rtnl_htb_class *htb;
552 int err;
553
554 if (!(htb = htb_class_data(class, &err)))
555 return err;
556
557 htb->ch_ceil.rs_cell_log = UINT8_MAX; /* use default value */
558 htb->ch_ceil.rs_rate64 = ceil64;
559 htb->ch_mask |= SCH_HTB_HAS_CEIL;
560
561 return 0;
562 }
563
564 /**
565 * Return burst buffer size of HTB class
566 * @arg class htb class object
567 *
568 * @return Burst buffer size or 0 if unspecified
569 */
rtnl_htb_get_rbuffer(struct rtnl_class * class)570 uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class)
571 {
572 struct rtnl_htb_class *htb;
573
574 if ((htb = htb_class_data(class, NULL)) &&
575 htb->ch_mask & SCH_HTB_HAS_RBUFFER)
576 return htb->ch_rbuffer;
577
578 return 0;
579 }
580
581 /**
582 * Set size of the rate bucket of HTB class.
583 * @arg class HTB class to be modified.
584 * @arg rbuffer New size in bytes.
585 */
rtnl_htb_set_rbuffer(struct rtnl_class * class,uint32_t rbuffer)586 int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer)
587 {
588 struct rtnl_htb_class *htb;
589 int err;
590
591 if (!(htb = htb_class_data(class, &err)))
592 return err;
593
594 htb->ch_rbuffer = rbuffer;
595 htb->ch_mask |= SCH_HTB_HAS_RBUFFER;
596
597 return 0;
598 }
599
600 /**
601 * Return ceil burst buffer size of HTB class
602 * @arg class htb class object
603 *
604 * @return Ceil burst buffer size or 0 if unspecified
605 */
rtnl_htb_get_cbuffer(struct rtnl_class * class)606 uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *class)
607 {
608 struct rtnl_htb_class *htb;
609
610 if ((htb = htb_class_data(class, NULL)) &&
611 htb->ch_mask & SCH_HTB_HAS_CBUFFER)
612 return htb->ch_cbuffer;
613
614 return 0;
615 }
616
617 /**
618 * Set size of the ceil bucket of HTB class.
619 * @arg class HTB class to be modified.
620 * @arg cbuffer New size in bytes.
621 */
rtnl_htb_set_cbuffer(struct rtnl_class * class,uint32_t cbuffer)622 int rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer)
623 {
624 struct rtnl_htb_class *htb;
625 int err;
626
627 if (!(htb = htb_class_data(class, &err)))
628 return err;
629
630 htb->ch_cbuffer = cbuffer;
631 htb->ch_mask |= SCH_HTB_HAS_CBUFFER;
632
633 return 0;
634 }
635
636 /**
637 * Return quantum of HTB class
638 * @arg class htb class object
639 *
640 * See XXX[quantum def]
641 *
642 * @return Quantum or 0 if unspecified.
643 */
rtnl_htb_get_quantum(struct rtnl_class * class)644 uint32_t rtnl_htb_get_quantum(struct rtnl_class *class)
645 {
646 struct rtnl_htb_class *htb;
647
648 if ((htb = htb_class_data(class, NULL)) &&
649 htb->ch_mask & SCH_HTB_HAS_QUANTUM)
650 return htb->ch_quantum;
651
652 return 0;
653 }
654
655 /**
656 * Set quantum of HTB class (overwrites value calculated based on r2q)
657 * @arg class htb class object
658 * @arg quantum new quantum in number of bytes
659 *
660 * See XXX[quantum def]
661 *
662 * @return 0 on success or a negative error code.
663 */
rtnl_htb_set_quantum(struct rtnl_class * class,uint32_t quantum)664 int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum)
665 {
666 struct rtnl_htb_class *htb;
667 int err;
668
669 if (!(htb = htb_class_data(class, &err)))
670 return err;
671
672 htb->ch_quantum = quantum;
673 htb->ch_mask |= SCH_HTB_HAS_QUANTUM;
674
675 return 0;
676 }
677
678 /**
679 * Return level of HTB class
680 * @arg class htb class object
681 *
682 * Returns the level of the HTB class. Leaf classes are assigned level
683 * 0, root classes have level (TC_HTB_MAXDEPTH - 1). Interior classes
684 * have a level of one less than their parent.
685 *
686 * @return Level or a negative error code.
687 */
rtnl_htb_get_level(struct rtnl_class * class)688 int rtnl_htb_get_level(struct rtnl_class *class)
689 {
690 struct rtnl_htb_class *htb;
691 int err = -NLE_OPNOTSUPP;
692
693 if ((htb = htb_class_data(class, &err)) &&
694 (htb->ch_mask & SCH_HTB_HAS_LEVEL))
695 return htb->ch_level;
696
697 return err;
698 }
699
700 /**
701 * Set level of HTB class
702 * @arg class htb class object
703 * @arg level new level of HTB class
704 *
705 * Sets the level of a HTB class. Note that changing the level of a HTB
706 * class does not change the level of its in kernel counterpart. This
707 * function is provided only to create HTB objects which can be compared
708 * against or filtered upon.
709 *
710 * @return 0 on success or a negative error code.
711 */
rtnl_htb_set_level(struct rtnl_class * class,int level)712 int rtnl_htb_set_level(struct rtnl_class *class, int level)
713 {
714 struct rtnl_htb_class *htb;
715 int err;
716
717 if (!(htb = htb_class_data(class, &err)))
718 return err;
719
720 htb->ch_level = level;
721 htb->ch_mask |= SCH_HTB_HAS_LEVEL;
722
723 return 0;
724 }
725
726 /** @} */
727
728 static struct rtnl_tc_ops htb_qdisc_ops = {
729 .to_kind = "htb",
730 .to_type = RTNL_TC_TYPE_QDISC,
731 .to_size = sizeof(struct rtnl_htb_qdisc),
732 .to_msg_parser = htb_qdisc_msg_parser,
733 .to_dump[NL_DUMP_LINE] = htb_qdisc_dump_line,
734 .to_msg_fill = htb_qdisc_msg_fill,
735 };
736
737 static struct rtnl_tc_ops htb_class_ops = {
738 .to_kind = "htb",
739 .to_type = RTNL_TC_TYPE_CLASS,
740 .to_size = sizeof(struct rtnl_htb_class),
741 .to_msg_parser = htb_class_msg_parser,
742 .to_dump = {
743 [NL_DUMP_LINE] = htb_class_dump_line,
744 [NL_DUMP_DETAILS] = htb_class_dump_details,
745 },
746 .to_msg_fill = htb_class_msg_fill,
747 };
748
htb_init(void)749 static void _nl_init htb_init(void)
750 {
751 rtnl_tc_register(&htb_qdisc_ops);
752 rtnl_tc_register(&htb_class_ops);
753 }
754
htb_exit(void)755 static void _nl_exit htb_exit(void)
756 {
757 rtnl_tc_unregister(&htb_qdisc_ops);
758 rtnl_tc_unregister(&htb_class_ops);
759 }
760
761 /** @} */
762