xref: /aosp_15_r20/external/libnl/lib/route/qdisc/htb.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
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