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