12#include <netlink-private/netlink.h>
13#include <netlink-private/tc.h>
14#include <netlink/netlink.h>
15#include <netlink/cache.h>
16#include <netlink/utils.h>
17#include <netlink-private/route/tc-api.h>
18#include <netlink/route/qdisc.h>
19#include <netlink/route/class.h>
20#include <netlink/route/link.h>
21#include <netlink/route/qdisc/tbf.h>
24#define TBF_ATTR_LIMIT 0x01
25#define TBF_ATTR_RATE 0x02
26#define TBF_ATTR_PEAKRATE 0x10
29static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = {
30 [TCA_TBF_PARMS] = { .
minlen =
sizeof(
struct tc_tbf_qopt) },
33static int tbf_msg_parser(
struct rtnl_tc *tc,
void *data)
35 struct nlattr *tb[TCA_TBF_MAX + 1];
36 struct rtnl_tbf *tbf = data;
39 if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0)
42 if (tb[TCA_TBF_PARMS]) {
43 struct tc_tbf_qopt opts;
46 nla_memcpy(&opts, tb[TCA_TBF_PARMS],
sizeof(opts));
47 tbf->qt_limit = opts.limit;
49 rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate);
50 tbf->qt_rate_txtime = opts.buffer;
51 bufsize = rtnl_tc_calc_bufsize64(
nl_ticks2us(opts.buffer),
52 tbf->qt_rate.rs_rate64);
53 tbf->qt_rate_bucket = bufsize;
55 rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate);
56 tbf->qt_peakrate_txtime = opts.mtu;
57 bufsize = rtnl_tc_calc_bufsize64(
nl_ticks2us(opts.mtu),
58 tbf->qt_peakrate.rs_rate64);
59 tbf->qt_peakrate_bucket = bufsize;
64 tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_RATE | TBF_ATTR_PEAKRATE);
70static void tbf_dump_line(
struct rtnl_tc *tc,
void *data,
74 char *ru, *rubit, *limu;
75 struct rtnl_tbf *tbf = data;
84 nl_dump(p,
" rate %.2f%s/s (%.0f%s) limit %.2f%s",
85 r, ru, rbit, rubit, lim, limu);
88static void tbf_dump_details(
struct rtnl_tc *tc,
void *data,
91 struct rtnl_tbf *tbf = data;
102 nl_dump(p,
"rate-bucket-size %1.f%s "
103 "rate-cell-size %.1f%s\n",
108 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
109 char *pru, *prbu, *bsu, *clu;
110 double pr, prb, bs, cl;
119 " peak-rate %.2f%s/s (%.0f%s) "
120 "bucket-size %.1f%s cell-size %.1f%s",
121 pr, pru, prb, prbu, bs, bsu, cl, clu);
125static int tbf_msg_fill(
struct rtnl_tc *tc,
void *data,
struct nl_msg *msg)
127 uint32_t rtab[RTNL_TC_RTABLE_SIZE], ptab[RTNL_TC_RTABLE_SIZE];
128 struct tc_tbf_qopt opts;
129 struct rtnl_tbf *tbf = data;
130 int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
132 if ((tbf->qt_mask & required) != required)
133 return -NLE_MISSING_ATTR;
135 memset(&opts, 0,
sizeof(opts));
136 opts.limit = tbf->qt_limit;
137 opts.buffer = tbf->qt_rate_txtime;
140 rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate);
142 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
143 opts.mtu = tbf->qt_peakrate_txtime;
145 rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate);
149 NLA_PUT(msg, TCA_TBF_PARMS,
sizeof(opts), &opts);
150 NLA_PUT(msg, TCA_TBF_RTAB,
sizeof(rtab), rtab);
152 if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
153 NLA_PUT(msg, TCA_TBF_PTAB,
sizeof(ptab), ptab);
174 struct rtnl_tbf *tbf;
179 tbf->qt_limit = limit;
180 tbf->qt_mask |= TBF_ATTR_LIMIT;
183static inline double calc_limit(
struct rtnl_ratespec *spec,
int latency,
188 limit = (double) spec->rs_rate64 * ((
double) latency / 1000000.);
214 struct rtnl_tbf *tbf;
215 double limit, limit2;
220 if (!(tbf->qt_mask & TBF_ATTR_RATE))
221 return -NLE_MISSING_ATTR;
223 limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket);
225 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
226 limit2 = calc_limit(&tbf->qt_peakrate, latency,
227 tbf->qt_peakrate_bucket);
245 struct rtnl_tbf *tbf;
250 if (tbf->qt_mask & TBF_ATTR_LIMIT)
251 return tbf->qt_limit;
256static inline int calc_cell_log(
int cell,
int bucket)
273 struct rtnl_tbf *tbf;
280 cell_log = UINT8_MAX;
284 tbf->qt_rate.rs_rate64 = (uint32_t)rate;
285 tbf->qt_rate_bucket = bucket;
286 tbf->qt_rate.rs_cell_log = cell_log;
287 tbf->qt_rate_txtime =
nl_us2ticks(rtnl_tc_calc_txtime64(bucket, tbf->qt_rate.rs_rate64));
288 tbf->qt_mask |= TBF_ATTR_RATE;
298 struct rtnl_tbf *tbf;
303 if (tbf->qt_mask & TBF_ATTR_RATE)
304 return tbf->qt_rate.rs_rate64;
316 struct rtnl_tbf *tbf;
321 if (tbf->qt_mask & TBF_ATTR_RATE)
322 return tbf->qt_rate_bucket;
334 struct rtnl_tbf *tbf;
339 if (tbf->qt_mask & TBF_ATTR_RATE)
340 return (1 << tbf->qt_rate.rs_cell_log);
356 struct rtnl_tbf *tbf;
362 cell_log = calc_cell_log(cell, bucket);
366 tbf->qt_peakrate.rs_rate64 = (uint32_t)rate;
367 tbf->qt_peakrate_bucket = bucket;
368 tbf->qt_peakrate.rs_cell_log = cell_log;
369 tbf->qt_peakrate_txtime =
nl_us2ticks(rtnl_tc_calc_txtime64(bucket, tbf->qt_peakrate.rs_rate64));
371 tbf->qt_mask |= TBF_ATTR_PEAKRATE;
383 struct rtnl_tbf *tbf;
388 if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
389 return tbf->qt_peakrate.rs_rate64;
401 struct rtnl_tbf *tbf;
406 if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
407 return tbf->qt_peakrate_bucket;
419 struct rtnl_tbf *tbf;
424 if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
425 return (1 << tbf->qt_peakrate.rs_cell_log);
432static struct rtnl_tc_ops tbf_tc_ops = {
434 .to_type = RTNL_TC_TYPE_QDISC,
435 .to_size =
sizeof(
struct rtnl_tbf),
436 .to_msg_parser = tbf_msg_parser,
441 .to_msg_fill = tbf_msg_fill,
444static void __init tbf_init(
void)
449static void __exit tbf_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 rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency)
Set limit of TBF qdisc by latency.
int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc)
Get rate of TBF qdisc.
int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc)
Get peak rate bucket size of TBF qdisc.
int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc)
Get rate cell size of TBF qdisc.
int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc)
Get rate bucket size of TBF qdisc.
void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit)
Set limit of TBF qdisc.
int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc)
Get limit of TBF qdisc.
int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket, int cell)
Set peak rate of TBF qdisc.
int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc)
Get peak rate cell size of TBF qdisc.
void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, int cell)
Set rate of TBF qdisc.
int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc)
Get peak rate of TBF qdisc.
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_tc_calc_cell_log(int cell_size)
Calculate the binary logarithm for a specific cell size.
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.
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control 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.
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.