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> 33 #define SCH_HTB_HAS_RATE2QUANTUM 0x01 34 #define SCH_HTB_HAS_DEFCLS 0x02 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 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) },
50 static int htb_qdisc_msg_parser(
struct rtnl_tc *tc,
void *data)
52 struct nlattr *tb[TCA_HTB_MAX + 1];
53 struct rtnl_htb_qdisc *htb = data;
56 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
59 if (tb[TCA_HTB_INIT]) {
60 struct tc_htb_glob opts;
62 nla_memcpy(&opts, tb[TCA_HTB_INIT],
sizeof(opts));
63 htb->qh_rate2quantum = opts.rate2quantum;
64 htb->qh_defcls = opts.defcls;
65 htb->qh_direct_pkts = opts.direct_pkts;
67 htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS);
73 static int htb_class_msg_parser(
struct rtnl_tc *tc,
void *data)
75 struct nlattr *tb[TCA_HTB_MAX + 1];
76 struct rtnl_htb_class *htb = data;
79 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
82 if (tb[TCA_HTB_PARMS]) {
83 struct tc_htb_opt opts;
85 nla_memcpy(&opts, tb[TCA_HTB_PARMS],
sizeof(opts));
86 htb->ch_prio = opts.prio;
87 rtnl_copy_ratespec(&htb->ch_rate, &opts.rate);
88 rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil);
93 htb->ch_quantum = opts.quantum;
94 htb->ch_level = opts.level;
99 htb->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE |
100 SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER |
101 SCH_HTB_HAS_CBUFFER | SCH_HTB_HAS_QUANTUM |
108 static void htb_qdisc_dump_line(
struct rtnl_tc *tc,
void *data,
111 struct rtnl_htb_qdisc *htb = data;
116 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
117 nl_dump(p,
" r2q %u", htb->qh_rate2quantum);
119 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) {
121 nl_dump(p,
" default-class %s",
126 static void htb_class_dump_line(
struct rtnl_tc *tc,
void *data,
129 struct rtnl_htb_class *htb = data;
134 if (htb->ch_mask & SCH_HTB_HAS_RATE) {
141 nl_dump(p,
" rate %.2f%s/s (%.0f%s) log %u",
142 r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log);
146 static void htb_class_dump_details(
struct rtnl_tc *tc,
void *data,
149 struct rtnl_htb_class *htb = data;
155 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
162 nl_dump(p,
" ceil %.2f%s/s (%.0f%s) log %u",
163 r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log);
166 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
167 nl_dump(p,
" prio %u", htb->ch_prio);
169 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) {
174 nl_dump(p,
" rbuffer %.2f%s", b, bu);
177 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) {
182 nl_dump(p,
" cbuffer %.2f%s", b, bu);
185 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
186 nl_dump(p,
" quantum %u", htb->ch_quantum);
189 static int htb_qdisc_msg_fill(
struct rtnl_tc *tc,
void *data,
192 struct rtnl_htb_qdisc *htb = data;
193 struct tc_htb_glob opts = {
194 .version = TC_HTB_PROTOVER,
199 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
200 opts.rate2quantum = htb->qh_rate2quantum;
202 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS)
203 opts.defcls = htb->qh_defcls;
206 return nla_put(msg, TCA_HTB_INIT,
sizeof(opts), &opts);
209 static int htb_class_msg_fill(
struct rtnl_tc *tc,
void *data,
212 struct rtnl_htb_class *htb = data;
213 uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE];
214 struct tc_htb_opt opts;
217 if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE))
220 memset(&opts, 0,
sizeof(opts));
223 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
224 opts.prio = htb->ch_prio;
229 rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate);
231 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
233 rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil);
239 memcpy(&opts.ceil, &opts.rate,
sizeof(
struct tc_ratespec));
242 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
243 buffer = htb->ch_rbuffer;
249 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
250 cbuffer = htb->ch_cbuffer;
256 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
257 opts.quantum = htb->ch_quantum;
259 NLA_PUT(msg, TCA_HTB_PARMS,
sizeof(opts), &opts);
260 NLA_PUT(msg, TCA_HTB_RTAB,
sizeof(rtable), &rtable);
261 NLA_PUT(msg, TCA_HTB_CTAB,
sizeof(ctable), &ctable);
269 static struct rtnl_tc_ops htb_qdisc_ops;
270 static struct rtnl_tc_ops htb_class_ops;
272 static struct rtnl_htb_qdisc *htb_qdisc_data(
struct rtnl_qdisc *qdisc,
int *err)
277 static struct rtnl_htb_class *htb_class_data(
struct rtnl_class *
class,
int *err)
295 struct rtnl_htb_qdisc *htb;
297 if ((htb = htb_qdisc_data(qdisc, NULL)) &&
298 (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM))
299 return htb->qh_rate2quantum;
304 int rtnl_htb_set_rate2quantum(
struct rtnl_qdisc *qdisc, uint32_t rate2quantum)
306 struct rtnl_htb_qdisc *htb;
309 if (!(htb = htb_qdisc_data(qdisc, &err)))
312 htb->qh_rate2quantum = rate2quantum;
313 htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM;
329 struct rtnl_htb_qdisc *htb;
331 if ((htb = htb_qdisc_data(qdisc, NULL)) &&
332 htb->qh_mask & SCH_HTB_HAS_DEFCLS)
333 return htb->qh_defcls;
345 struct rtnl_htb_qdisc *htb;
348 if (!(htb = htb_qdisc_data(qdisc, &err)))
351 htb->qh_defcls = defcls;
352 htb->qh_mask |= SCH_HTB_HAS_DEFCLS;
357 uint32_t rtnl_htb_get_prio(
struct rtnl_class *
class)
359 struct rtnl_htb_class *htb;
361 if ((htb = htb_class_data(
class, NULL)) &&
362 (htb->ch_mask & SCH_HTB_HAS_PRIO))
368 int rtnl_htb_set_prio(
struct rtnl_class *
class, uint32_t prio)
370 struct rtnl_htb_class *htb;
373 if (!(htb = htb_class_data(
class, &err)))
377 htb->ch_mask |= SCH_HTB_HAS_PRIO;
390 struct rtnl_htb_class *htb;
392 if ((htb = htb_class_data(
class, NULL)) &&
393 (htb->ch_mask & SCH_HTB_HAS_RATE))
394 return htb->ch_rate.rs_rate;
408 struct rtnl_htb_class *htb;
411 if (!(htb = htb_class_data(
class, &err)))
414 htb->ch_rate.rs_cell_log = UINT8_MAX;
415 htb->ch_rate.rs_rate = rate;
416 htb->ch_mask |= SCH_HTB_HAS_RATE;
429 struct rtnl_htb_class *htb;
431 if ((htb = htb_class_data(
class, NULL)) &&
432 (htb->ch_mask & SCH_HTB_HAS_CEIL))
433 return htb->ch_ceil.rs_rate;
447 struct rtnl_htb_class *htb;
450 if (!(htb = htb_class_data(
class, &err)))
453 htb->ch_ceil.rs_cell_log = UINT8_MAX;
454 htb->ch_ceil.rs_rate = ceil;
455 htb->ch_mask |= SCH_HTB_HAS_CEIL;
468 struct rtnl_htb_class *htb;
470 if ((htb = htb_class_data(
class, NULL)) &&
471 htb->ch_mask & SCH_HTB_HAS_RBUFFER)
472 return htb->ch_rbuffer;
484 struct rtnl_htb_class *htb;
487 if (!(htb = htb_class_data(
class, &err)))
490 htb->ch_rbuffer = rbuffer;
491 htb->ch_mask |= SCH_HTB_HAS_RBUFFER;
504 struct rtnl_htb_class *htb;
506 if ((htb = htb_class_data(
class, NULL)) &&
507 htb->ch_mask & SCH_HTB_HAS_CBUFFER)
508 return htb->ch_cbuffer;
520 struct rtnl_htb_class *htb;
523 if (!(htb = htb_class_data(
class, &err)))
526 htb->ch_cbuffer = cbuffer;
527 htb->ch_mask |= SCH_HTB_HAS_CBUFFER;
542 struct rtnl_htb_class *htb;
544 if ((htb = htb_class_data(
class, NULL)) &&
545 htb->ch_mask & SCH_HTB_HAS_QUANTUM)
546 return htb->ch_quantum;
562 struct rtnl_htb_class *htb;
565 if (!(htb = htb_class_data(
class, &err)))
568 htb->ch_quantum = quantum;
569 htb->ch_mask |= SCH_HTB_HAS_QUANTUM;
586 struct rtnl_htb_class *htb;
587 int err = -NLE_OPNOTSUPP;
589 if ((htb = htb_class_data(
class, &err)) &&
590 (htb->ch_mask & SCH_HTB_HAS_LEVEL))
591 return htb->ch_level;
610 struct rtnl_htb_class *htb;
613 if (!(htb = htb_class_data(
class, &err)))
616 htb->ch_level = level;
617 htb->ch_mask |= SCH_HTB_HAS_LEVEL;
624 static struct rtnl_tc_ops htb_qdisc_ops = {
626 .to_type = RTNL_TC_TYPE_QDISC,
627 .to_size =
sizeof(
struct rtnl_htb_qdisc),
628 .to_msg_parser = htb_qdisc_msg_parser,
630 .to_msg_fill = htb_qdisc_msg_fill,
633 static struct rtnl_tc_ops htb_class_ops = {
635 .to_type = RTNL_TC_TYPE_CLASS,
636 .to_size =
sizeof(
struct rtnl_htb_class),
637 .to_msg_parser = htb_class_msg_parser,
642 .to_msg_fill = htb_class_msg_fill,
645 static void __init htb_init(
void)
651 static void __exit htb_exit(
void)
int rtnl_htb_get_level(struct rtnl_class *class)
Return level of HTB class.
int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer)
Set size of the rate bucket of HTB class.
Dump object briefly on one line.
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
int rtnl_tc_calc_txtime(int bufsize, int rate)
Calculate time required to transmit buffer at a specific rate.
int rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer)
Set size of the ceil bucket of HTB class.
uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
Return rate of HTB class.
int rtnl_htb_set_level(struct rtnl_class *class, int level)
Set level of HTB class.
uint32_t rtnl_htb_get_quantum(struct rtnl_class *class)
Return quantum of HTB class.
Attribute validation policy.
double nl_cancel_down_bits(unsigned long long l, char **unit)
Cancel down a bit counter.
uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc)
Return default class of HTB qdisc.
Dump all attributes but no statistics.
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.
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class)
Return burst buffer size of HTB class.
int rtnl_tc_calc_bufsize(int txtime, int rate)
Calculate buffer size able to transmit in a specific time and rate.
uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc)
Return the MTU of traffic control object.
double nl_cancel_down_bytes(unsigned long long l, char **unit)
Cancel down a byte counter.
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *class)
Return ceil burst buffer size of HTB class.
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
int nl_get_psched_hz(void)
Return the value of packet scheduler HZ.
int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
Set ceil rate of HTB class.
uint32_t nl_ticks2us(uint32_t ticks)
Convert ticks to micro seconds.
int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
Set rate of HTB class.
uint16_t minlen
Minimal length of payload required.
void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu)
Set the Minimum Packet Unit (MPU) of a traffic control object.
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_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
Set default class of the htb qdisc to the specified value.
uint32_t nl_us2ticks(uint32_t us)
Convert micro seconds to ticks.
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
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_htb_get_rate2quantum(struct rtnl_qdisc *qdisc)
Return rate/quantum ratio of HTB qdisc.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
uint32_t rtnl_htb_get_ceil(struct rtnl_class *class)
Return ceil rate of HTB class.
int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
Add a unspecific attribute to netlink message.