18 #include <netlink-private/netlink.h>
19 #include <netlink-private/tc.h>
20 #include <netlink/netlink.h>
21 #include <netlink/cache.h>
22 #include <netlink/utils.h>
23 #include <netlink-private/route/tc-api.h>
24 #include <netlink/route/qdisc.h>
25 #include <netlink/route/class.h>
26 #include <netlink/route/link.h>
27 #include <netlink/route/qdisc/tbf.h>
30 #define TBF_ATTR_LIMIT 0x01
31 #define TBF_ATTR_RATE 0x02
32 #define TBF_ATTR_PEAKRATE 0x10
35 static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = {
36 [TCA_TBF_PARMS] = { .
minlen =
sizeof(
struct tc_tbf_qopt) },
39 static int tbf_msg_parser(
struct rtnl_tc *tc,
void *data)
41 struct nlattr *tb[TCA_TBF_MAX + 1];
42 struct rtnl_tbf *tbf = data;
45 if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0)
48 if (tb[TCA_TBF_PARMS]) {
49 struct tc_tbf_qopt opts;
52 nla_memcpy(&opts, tb[TCA_TBF_PARMS],
sizeof(opts));
53 tbf->qt_limit = opts.limit;
55 rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate);
56 tbf->qt_rate_txtime = opts.buffer;
59 tbf->qt_rate_bucket = bufsize;
61 rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate);
62 tbf->qt_peakrate_txtime = opts.mtu;
65 tbf->qt_peakrate_bucket = bufsize;
70 tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_RATE | TBF_ATTR_PEAKRATE);
76 static void tbf_dump_line(
struct rtnl_tc *tc,
void *data,
80 char *ru, *rubit, *limu;
81 struct rtnl_tbf *tbf = data;
90 nl_dump(p,
" rate %.2f%s/s (%.0f%s) limit %.2f%s",
91 r, ru, rbit, rubit, lim, limu);
94 static void tbf_dump_details(
struct rtnl_tc *tc,
void *data,
97 struct rtnl_tbf *tbf = data;
108 nl_dump(p,
"rate-bucket-size %1.f%s "
109 "rate-cell-size %.1f%s\n",
114 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
115 char *pru, *prbu, *bsu, *clu;
116 double pr, prb, bs, cl;
124 nl_dump_line(p,
" peak-rate %.2f%s/s (%.0f%s) "
125 "bucket-size %.1f%s cell-size %.1f%s"
127 pr, pru, prb, prbu, bs, bsu, cl, clu);
131 static int tbf_msg_fill(
struct rtnl_tc *tc,
void *data,
struct nl_msg *msg)
133 uint32_t rtab[RTNL_TC_RTABLE_SIZE], ptab[RTNL_TC_RTABLE_SIZE];
134 struct tc_tbf_qopt opts;
135 struct rtnl_tbf *tbf = data;
136 int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
138 if ((tbf->qt_mask & required) != required)
139 return -NLE_MISSING_ATTR;
141 memset(&opts, 0,
sizeof(opts));
142 opts.limit = tbf->qt_limit;
143 opts.buffer = tbf->qt_rate_txtime;
146 rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate);
148 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
149 opts.mtu = tbf->qt_peakrate_txtime;
151 rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate);
155 NLA_PUT(msg, TCA_TBF_PARMS,
sizeof(opts), &opts);
156 NLA_PUT(msg, TCA_TBF_RTAB,
sizeof(rtab), rtab);
158 if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
159 NLA_PUT(msg, TCA_TBF_PTAB,
sizeof(ptab), ptab);
180 struct rtnl_tbf *tbf;
185 tbf->qt_limit = limit;
186 tbf->qt_mask |= TBF_ATTR_LIMIT;
189 static inline double calc_limit(
struct rtnl_ratespec *spec,
int latency,
194 limit = (double) spec->rs_rate * ((
double) latency / 1000000.);
220 struct rtnl_tbf *tbf;
221 double limit, limit2;
226 if (!(tbf->qt_mask & TBF_ATTR_RATE))
227 return -NLE_MISSING_ATTR;
229 limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket);
231 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
232 limit2 = calc_limit(&tbf->qt_peakrate, latency,
233 tbf->qt_peakrate_bucket);
251 struct rtnl_tbf *tbf;
256 if (tbf->qt_mask & TBF_ATTR_LIMIT)
257 return tbf->qt_limit;
262 static inline int calc_cell_log(
int cell,
int bucket)
279 struct rtnl_tbf *tbf;
286 cell_log = UINT8_MAX;
290 tbf->qt_rate.rs_rate = rate;
291 tbf->qt_rate_bucket = bucket;
292 tbf->qt_rate.rs_cell_log = cell_log;
294 tbf->qt_mask |= TBF_ATTR_RATE;
304 struct rtnl_tbf *tbf;
309 if (tbf->qt_mask & TBF_ATTR_RATE)
310 return tbf->qt_rate.rs_rate;
322 struct rtnl_tbf *tbf;
327 if (tbf->qt_mask & TBF_ATTR_RATE)
328 return tbf->qt_rate_bucket;
340 struct rtnl_tbf *tbf;
345 if (tbf->qt_mask & TBF_ATTR_RATE)
346 return (1 << tbf->qt_rate.rs_cell_log);
362 struct rtnl_tbf *tbf;
368 cell_log = calc_cell_log(cell, bucket);
372 tbf->qt_peakrate.rs_rate = rate;
373 tbf->qt_peakrate_bucket = bucket;
374 tbf->qt_peakrate.rs_cell_log = cell_log;
377 tbf->qt_mask |= TBF_ATTR_PEAKRATE;
389 struct rtnl_tbf *tbf;
394 if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
395 return tbf->qt_peakrate.rs_rate;
407 struct rtnl_tbf *tbf;
412 if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
413 return tbf->qt_peakrate_bucket;
425 struct rtnl_tbf *tbf;
430 if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
431 return (1 << tbf->qt_peakrate.rs_cell_log);
438 static struct rtnl_tc_ops tbf_tc_ops = {
440 .to_type = RTNL_TC_TYPE_QDISC,
441 .to_size =
sizeof(
struct rtnl_tbf),
442 .to_msg_parser = tbf_msg_parser,
447 .to_msg_fill = tbf_msg_fill,
450 static void __init tbf_init(
void)
455 static void __exit tbf_exit(
void)