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>
27#define SCH_HTB_HAS_RATE2QUANTUM 0x01
28#define SCH_HTB_HAS_DEFCLS 0x02
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
39static 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) },
46static int htb_qdisc_msg_parser(
struct rtnl_tc *tc,
void *data)
48 struct nlattr *tb[TCA_HTB_MAX + 1];
49 struct rtnl_htb_qdisc *htb = data;
52 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
55 if (tb[TCA_HTB_INIT]) {
56 struct tc_htb_glob opts;
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;
63 htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS);
69static int htb_class_msg_parser(
struct rtnl_tc *tc,
void *data)
71 struct nlattr *tb[TCA_HTB_MAX + 1];
72 struct rtnl_htb_class *htb = data;
75 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
78 if (tb[TCA_HTB_PARMS]) {
79 struct tc_htb_opt opts;
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);
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));
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;
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 |
110static void htb_qdisc_dump_line(
struct rtnl_tc *tc,
void *data,
113 struct rtnl_htb_qdisc *htb = data;
118 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
119 nl_dump(p,
" r2q %u", htb->qh_rate2quantum);
121 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) {
123 nl_dump(p,
" default-class %s",
128static void htb_class_dump_line(
struct rtnl_tc *tc,
void *data,
131 struct rtnl_htb_class *htb = data;
136 if (htb->ch_mask & SCH_HTB_HAS_RATE) {
143 nl_dump(p,
" rate %.2f%s/s (%.0f%s) log %u",
144 r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log);
148static void htb_class_dump_details(
struct rtnl_tc *tc,
void *data,
151 struct rtnl_htb_class *htb = data;
157 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
164 nl_dump(p,
" ceil %.2f%s/s (%.0f%s) log %u",
165 r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log);
168 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
169 nl_dump(p,
" prio %u", htb->ch_prio);
171 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) {
176 nl_dump(p,
" rbuffer %.2f%s", b, bu);
179 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) {
184 nl_dump(p,
" cbuffer %.2f%s", b, bu);
187 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
188 nl_dump(p,
" quantum %u", htb->ch_quantum);
191static int htb_qdisc_msg_fill(
struct rtnl_tc *tc,
void *data,
194 struct rtnl_htb_qdisc *htb = data;
195 struct tc_htb_glob opts = {
196 .version = TC_HTB_PROTOVER,
201 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
202 opts.rate2quantum = htb->qh_rate2quantum;
204 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS)
205 opts.defcls = htb->qh_defcls;
208 return nla_put(msg, TCA_HTB_INIT,
sizeof(opts), &opts);
211static int htb_class_msg_fill(
struct rtnl_tc *tc,
void *data,
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;
221 if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE))
224 memset(&opts, 0,
sizeof(opts));
227 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
228 opts.prio = htb->ch_prio;
233 rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate);
234 rate64 = htb->ch_rate.rs_rate64;
236 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
238 rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil);
239 ceil64 = htb->ch_ceil.rs_rate64;
245 memcpy(&opts.ceil, &opts.rate,
sizeof(
struct tc_ratespec));
249 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
250 buffer = htb->ch_rbuffer;
254 opts.buffer =
nl_us2ticks(rtnl_tc_calc_txtime64(buffer, rate64));
256 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
257 cbuffer = htb->ch_cbuffer;
261 opts.cbuffer =
nl_us2ticks(rtnl_tc_calc_txtime64(cbuffer, ceil64));
263 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
264 opts.quantum = htb->ch_quantum;
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);
280static struct rtnl_tc_ops htb_qdisc_ops;
281static struct rtnl_tc_ops htb_class_ops;
283static struct rtnl_htb_qdisc *htb_qdisc_data(
struct rtnl_qdisc *qdisc,
int *err)
288static struct rtnl_htb_class *htb_class_data(
struct rtnl_class *
class,
int *err)
306 struct rtnl_htb_qdisc *htb;
308 if ((htb = htb_qdisc_data(qdisc, NULL)) &&
309 (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM))
310 return htb->qh_rate2quantum;
315int rtnl_htb_set_rate2quantum(
struct rtnl_qdisc *qdisc, uint32_t rate2quantum)
317 struct rtnl_htb_qdisc *htb;
320 if (!(htb = htb_qdisc_data(qdisc, &err)))
323 htb->qh_rate2quantum = rate2quantum;
324 htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM;
340 struct rtnl_htb_qdisc *htb;
342 if ((htb = htb_qdisc_data(qdisc, NULL)) &&
343 htb->qh_mask & SCH_HTB_HAS_DEFCLS)
344 return htb->qh_defcls;
356 struct rtnl_htb_qdisc *htb;
359 if (!(htb = htb_qdisc_data(qdisc, &err)))
362 htb->qh_defcls = defcls;
363 htb->qh_mask |= SCH_HTB_HAS_DEFCLS;
368uint32_t rtnl_htb_get_prio(
struct rtnl_class *
class)
370 struct rtnl_htb_class *htb;
372 if ((htb = htb_class_data(
class, NULL)) &&
373 (htb->ch_mask & SCH_HTB_HAS_PRIO))
379int rtnl_htb_set_prio(
struct rtnl_class *
class, uint32_t prio)
381 struct rtnl_htb_class *htb;
384 if (!(htb = htb_class_data(
class, &err)))
388 htb->ch_mask |= SCH_HTB_HAS_PRIO;
403 struct rtnl_htb_class *htb;
405 if ( !(htb = htb_class_data(
class, NULL))
406 || !(htb->ch_mask & SCH_HTB_HAS_RATE))
409 if (htb->ch_rate.rs_rate64 > 0xFFFFFFFFull)
410 return 0xFFFFFFFFull;
412 return htb->ch_rate.rs_rate64;
424 struct rtnl_htb_class *htb;
426 if (!(htb = htb_class_data(
class, NULL)))
428 if (!(htb->ch_mask & SCH_HTB_HAS_RATE))
431 *out_rate64 = htb->ch_rate.rs_rate64;
456 struct rtnl_htb_class *htb;
459 if (!(htb = htb_class_data(
class, &err)))
462 htb->ch_rate.rs_cell_log = UINT8_MAX;
463 htb->ch_rate.rs_rate64 = rate;
464 htb->ch_mask |= SCH_HTB_HAS_RATE;
479 struct rtnl_htb_class *htb;
481 if ( !(htb = htb_class_data(
class, NULL))
482 || !(htb->ch_mask & SCH_HTB_HAS_CEIL))
485 if (htb->ch_ceil.rs_rate64 > 0xFFFFFFFFull)
486 return 0xFFFFFFFFull;
488 return htb->ch_ceil.rs_rate64;
500 struct rtnl_htb_class *htb;
502 if (!(htb = htb_class_data(
class, NULL)))
504 if (!(htb->ch_mask & SCH_HTB_HAS_CEIL))
507 *out_ceil64 = htb->ch_ceil.rs_rate64;
532 struct rtnl_htb_class *htb;
535 if (!(htb = htb_class_data(
class, &err)))
538 htb->ch_ceil.rs_cell_log = UINT8_MAX;
539 htb->ch_ceil.rs_rate64 = ceil64;
540 htb->ch_mask |= SCH_HTB_HAS_CEIL;
553 struct rtnl_htb_class *htb;
555 if ((htb = htb_class_data(
class, NULL)) &&
556 htb->ch_mask & SCH_HTB_HAS_RBUFFER)
557 return htb->ch_rbuffer;
569 struct rtnl_htb_class *htb;
572 if (!(htb = htb_class_data(
class, &err)))
575 htb->ch_rbuffer = rbuffer;
576 htb->ch_mask |= SCH_HTB_HAS_RBUFFER;
589 struct rtnl_htb_class *htb;
591 if ((htb = htb_class_data(
class, NULL)) &&
592 htb->ch_mask & SCH_HTB_HAS_CBUFFER)
593 return htb->ch_cbuffer;
605 struct rtnl_htb_class *htb;
608 if (!(htb = htb_class_data(
class, &err)))
611 htb->ch_cbuffer = cbuffer;
612 htb->ch_mask |= SCH_HTB_HAS_CBUFFER;
627 struct rtnl_htb_class *htb;
629 if ((htb = htb_class_data(
class, NULL)) &&
630 htb->ch_mask & SCH_HTB_HAS_QUANTUM)
631 return htb->ch_quantum;
647 struct rtnl_htb_class *htb;
650 if (!(htb = htb_class_data(
class, &err)))
653 htb->ch_quantum = quantum;
654 htb->ch_mask |= SCH_HTB_HAS_QUANTUM;
671 struct rtnl_htb_class *htb;
672 int err = -NLE_OPNOTSUPP;
674 if ((htb = htb_class_data(
class, &err)) &&
675 (htb->ch_mask & SCH_HTB_HAS_LEVEL))
676 return htb->ch_level;
695 struct rtnl_htb_class *htb;
698 if (!(htb = htb_class_data(
class, &err)))
701 htb->ch_level = level;
702 htb->ch_mask |= SCH_HTB_HAS_LEVEL;
709static struct rtnl_tc_ops htb_qdisc_ops = {
711 .to_type = RTNL_TC_TYPE_QDISC,
712 .to_size =
sizeof(
struct rtnl_htb_qdisc),
713 .to_msg_parser = htb_qdisc_msg_parser,
715 .to_msg_fill = htb_qdisc_msg_fill,
718static struct rtnl_tc_ops htb_class_ops = {
720 .to_type = RTNL_TC_TYPE_CLASS,
721 .to_size =
sizeof(
struct rtnl_htb_class),
722 .to_msg_parser = htb_class_msg_parser,
727 .to_msg_fill = htb_class_msg_fill,
730static void __init htb_init(
void)
736static void __exit htb_exit(
void)
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
Add a unspecific attribute to netlink message.
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer)
Set size of the rate bucket of HTB class.
int rtnl_htb_set_level(struct rtnl_class *class, int level)
Set level of HTB class.
uint32_t rtnl_htb_get_ceil(struct rtnl_class *class)
Return ceil rate of HTB class.
int rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
Set default class of the htb qdisc to the specified value.
uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc)
Return default class of HTB qdisc.
int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum)
Set quantum of HTB class (overwrites value calculated based on r2q)
int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
Set rate of HTB class.
int rtnl_htb_get_ceil64(struct rtnl_class *class, uint64_t *out_ceil64)
Return ceil rate of HTB class.
int rtnl_htb_get_rate64(struct rtnl_class *class, uint64_t *out_rate64)
Return rate of HTB class.
uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc)
Return rate/quantum ratio of HTB qdisc.
int rtnl_htb_set_rate64(struct rtnl_class *class, uint64_t rate)
Set rate of HTB class.
uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class)
Return burst buffer size of HTB class.
int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
Set ceil rate of HTB class.
int rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer)
Set size of the ceil bucket of HTB class.
int rtnl_htb_set_ceil64(struct rtnl_class *class, uint64_t ceil64)
Set ceil rate of HTB class.
uint32_t rtnl_htb_get_quantum(struct rtnl_class *class)
Return quantum of HTB class.
uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
Return rate of HTB class.
uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *class)
Return ceil burst buffer size of HTB class.
int rtnl_htb_get_level(struct rtnl_class *class)
Return level of HTB class.
void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu)
Set the Minimum Packet Unit (MPU) of a traffic control object.
void * rtnl_tc_data_check(struct rtnl_tc *tc, struct rtnl_tc_ops *ops, int *err)
Check traffic control object type and return private data section.
int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec, uint32_t *dst)
Compute a transmission time lookup table.
void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead)
Set per packet overhead of a traffic control object.
uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc)
Return the MTU of traffic control object.
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
int nl_get_psched_hz(void)
Return the value of packet scheduler HZ.
double nl_cancel_down_bits(unsigned long long l, char **unit)
Cancel down a bit counter.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
double nl_cancel_down_bytes(unsigned long long l, char **unit)
Cancel down a byte counter.
uint32_t nl_ticks2us(uint32_t ticks)
Convert ticks to micro seconds.
uint32_t nl_us2ticks(uint32_t us)
Convert micro seconds to ticks.
@ NL_DUMP_LINE
Dump object briefly on one line.
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Attribute validation policy.
uint16_t minlen
Minimal length of payload required.