15#include "nl-default.h"
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>
28struct rtnl_htb_qdisc {
29 uint32_t qh_rate2quantum;
32 uint32_t qh_direct_pkts;
35struct rtnl_htb_class {
46#define SCH_HTB_HAS_RATE2QUANTUM 0x01
47#define SCH_HTB_HAS_DEFCLS 0x02
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
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) },
65static int htb_qdisc_msg_parser(
struct rtnl_tc *tc,
void *data)
67 struct nlattr *tb[TCA_HTB_MAX + 1];
68 struct rtnl_htb_qdisc *htb = data;
71 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
74 if (tb[TCA_HTB_INIT]) {
75 struct tc_htb_glob opts;
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;
82 htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS);
88static int htb_class_msg_parser(
struct rtnl_tc *tc,
void *data)
90 struct nlattr *tb[TCA_HTB_MAX + 1];
91 struct rtnl_htb_class *htb = data;
94 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
97 if (tb[TCA_HTB_PARMS]) {
98 struct tc_htb_opt opts;
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);
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));
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;
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 |
129static void htb_qdisc_dump_line(
struct rtnl_tc *tc,
void *data,
132 struct rtnl_htb_qdisc *htb = data;
137 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
138 nl_dump(p,
" r2q %u", htb->qh_rate2quantum);
140 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) {
142 nl_dump(p,
" default-class %s",
147static void htb_class_dump_line(
struct rtnl_tc *tc,
void *data,
150 struct rtnl_htb_class *htb = data;
155 if (htb->ch_mask & SCH_HTB_HAS_RATE) {
162 nl_dump(p,
" rate %.2f%s/s (%.0f%s) log %u",
163 r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log);
167static void htb_class_dump_details(
struct rtnl_tc *tc,
void *data,
170 struct rtnl_htb_class *htb = data;
176 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
183 nl_dump(p,
" ceil %.2f%s/s (%.0f%s) log %u",
184 r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log);
187 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
188 nl_dump(p,
" prio %u", htb->ch_prio);
190 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) {
195 nl_dump(p,
" rbuffer %.2f%s", b, bu);
198 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) {
203 nl_dump(p,
" cbuffer %.2f%s", b, bu);
206 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
207 nl_dump(p,
" quantum %u", htb->ch_quantum);
210static int htb_qdisc_msg_fill(
struct rtnl_tc *tc,
void *data,
213 struct rtnl_htb_qdisc *htb = data;
214 struct tc_htb_glob opts = {
215 .version = TC_HTB_PROTOVER,
220 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
221 opts.rate2quantum = htb->qh_rate2quantum;
223 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS)
224 opts.defcls = htb->qh_defcls;
227 return nla_put(msg, TCA_HTB_INIT,
sizeof(opts), &opts);
230static int htb_class_msg_fill(
struct rtnl_tc *tc,
void *data,
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;
240 if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE))
243 memset(&opts, 0,
sizeof(opts));
246 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
247 opts.prio = htb->ch_prio;
252 rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate);
253 rate64 = htb->ch_rate.rs_rate64;
255 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
257 rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil);
258 ceil64 = htb->ch_ceil.rs_rate64;
264 memcpy(&opts.ceil, &opts.rate,
sizeof(
struct tc_ratespec));
268 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
269 buffer = htb->ch_rbuffer;
273 opts.buffer =
nl_us2ticks(rtnl_tc_calc_txtime64(buffer, rate64));
275 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
276 cbuffer = htb->ch_cbuffer;
280 opts.cbuffer =
nl_us2ticks(rtnl_tc_calc_txtime64(cbuffer, ceil64));
282 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
283 opts.quantum = htb->ch_quantum;
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);
299static struct rtnl_tc_ops htb_qdisc_ops;
300static struct rtnl_tc_ops htb_class_ops;
302static struct rtnl_htb_qdisc *htb_qdisc_data(
struct rtnl_qdisc *qdisc,
int *err)
307static struct rtnl_htb_class *htb_class_data(
struct rtnl_class *
class,
int *err)
325 struct rtnl_htb_qdisc *htb;
327 if ((htb = htb_qdisc_data(qdisc, NULL)) &&
328 (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM))
329 return htb->qh_rate2quantum;
334int rtnl_htb_set_rate2quantum(
struct rtnl_qdisc *qdisc, uint32_t rate2quantum)
336 struct rtnl_htb_qdisc *htb;
339 if (!(htb = htb_qdisc_data(qdisc, &err)))
342 htb->qh_rate2quantum = rate2quantum;
343 htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM;
359 struct rtnl_htb_qdisc *htb;
361 if ((htb = htb_qdisc_data(qdisc, NULL)) &&
362 htb->qh_mask & SCH_HTB_HAS_DEFCLS)
363 return htb->qh_defcls;
375 struct rtnl_htb_qdisc *htb;
378 if (!(htb = htb_qdisc_data(qdisc, &err)))
381 htb->qh_defcls = defcls;
382 htb->qh_mask |= SCH_HTB_HAS_DEFCLS;
387uint32_t rtnl_htb_get_prio(
struct rtnl_class *
class)
389 struct rtnl_htb_class *htb;
391 if ((htb = htb_class_data(
class, NULL)) &&
392 (htb->ch_mask & SCH_HTB_HAS_PRIO))
398int rtnl_htb_set_prio(
struct rtnl_class *
class, uint32_t prio)
400 struct rtnl_htb_class *htb;
403 if (!(htb = htb_class_data(
class, &err)))
407 htb->ch_mask |= SCH_HTB_HAS_PRIO;
422 struct rtnl_htb_class *htb;
424 if ( !(htb = htb_class_data(
class, NULL))
425 || !(htb->ch_mask & SCH_HTB_HAS_RATE))
428 if (htb->ch_rate.rs_rate64 > 0xFFFFFFFFull)
429 return 0xFFFFFFFFull;
431 return htb->ch_rate.rs_rate64;
443 struct rtnl_htb_class *htb;
445 if (!(htb = htb_class_data(
class, NULL)))
447 if (!(htb->ch_mask & SCH_HTB_HAS_RATE))
450 *out_rate64 = htb->ch_rate.rs_rate64;
475 struct rtnl_htb_class *htb;
478 if (!(htb = htb_class_data(
class, &err)))
481 htb->ch_rate.rs_cell_log = UINT8_MAX;
482 htb->ch_rate.rs_rate64 = rate;
483 htb->ch_mask |= SCH_HTB_HAS_RATE;
498 struct rtnl_htb_class *htb;
500 if ( !(htb = htb_class_data(
class, NULL))
501 || !(htb->ch_mask & SCH_HTB_HAS_CEIL))
504 if (htb->ch_ceil.rs_rate64 > 0xFFFFFFFFull)
505 return 0xFFFFFFFFull;
507 return htb->ch_ceil.rs_rate64;
519 struct rtnl_htb_class *htb;
521 if (!(htb = htb_class_data(
class, NULL)))
523 if (!(htb->ch_mask & SCH_HTB_HAS_CEIL))
526 *out_ceil64 = htb->ch_ceil.rs_rate64;
551 struct rtnl_htb_class *htb;
554 if (!(htb = htb_class_data(
class, &err)))
557 htb->ch_ceil.rs_cell_log = UINT8_MAX;
558 htb->ch_ceil.rs_rate64 = ceil64;
559 htb->ch_mask |= SCH_HTB_HAS_CEIL;
572 struct rtnl_htb_class *htb;
574 if ((htb = htb_class_data(
class, NULL)) &&
575 htb->ch_mask & SCH_HTB_HAS_RBUFFER)
576 return htb->ch_rbuffer;
588 struct rtnl_htb_class *htb;
591 if (!(htb = htb_class_data(
class, &err)))
594 htb->ch_rbuffer = rbuffer;
595 htb->ch_mask |= SCH_HTB_HAS_RBUFFER;
608 struct rtnl_htb_class *htb;
610 if ((htb = htb_class_data(
class, NULL)) &&
611 htb->ch_mask & SCH_HTB_HAS_CBUFFER)
612 return htb->ch_cbuffer;
624 struct rtnl_htb_class *htb;
627 if (!(htb = htb_class_data(
class, &err)))
630 htb->ch_cbuffer = cbuffer;
631 htb->ch_mask |= SCH_HTB_HAS_CBUFFER;
646 struct rtnl_htb_class *htb;
648 if ((htb = htb_class_data(
class, NULL)) &&
649 htb->ch_mask & SCH_HTB_HAS_QUANTUM)
650 return htb->ch_quantum;
666 struct rtnl_htb_class *htb;
669 if (!(htb = htb_class_data(
class, &err)))
672 htb->ch_quantum = quantum;
673 htb->ch_mask |= SCH_HTB_HAS_QUANTUM;
690 struct rtnl_htb_class *htb;
691 int err = -NLE_OPNOTSUPP;
693 if ((htb = htb_class_data(
class, &err)) &&
694 (htb->ch_mask & SCH_HTB_HAS_LEVEL))
695 return htb->ch_level;
714 struct rtnl_htb_class *htb;
717 if (!(htb = htb_class_data(
class, &err)))
720 htb->ch_level = level;
721 htb->ch_mask |= SCH_HTB_HAS_LEVEL;
728static struct rtnl_tc_ops htb_qdisc_ops = {
730 .to_type = RTNL_TC_TYPE_QDISC,
731 .to_size =
sizeof(
struct rtnl_htb_qdisc),
732 .to_msg_parser = htb_qdisc_msg_parser,
734 .to_msg_fill = htb_qdisc_msg_fill,
737static struct rtnl_tc_ops htb_class_ops = {
739 .to_type = RTNL_TC_TYPE_CLASS,
740 .to_size =
sizeof(
struct rtnl_htb_class),
741 .to_msg_parser = htb_class_msg_parser,
746 .to_msg_fill = htb_class_msg_fill,
749static void _nl_init htb_init(
void)
755static void _nl_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 *, struct rtnl_tc_ops *, int *)
Check traffic control object type and return private data section.
int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *, uint32_t *)
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 *)
Register a traffic control module.
void rtnl_tc_unregister(struct rtnl_tc_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.
uint16_t type
Type of attribute or NLA_UNSPEC.