• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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