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