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