tbf.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. /*
  2. * lib/route/qdisc/tbf.c TBF Qdisc
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation version 2.1
  7. * of the License.
  8. *
  9. * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
  10. */
  11. /**
  12. * @ingroup qdisc
  13. * @defgroup qdisc_tbf Token Bucket Filter (TBF)
  14. * @{
  15. */
  16. #include <netlink-private/netlink.h>
  17. #include <netlink-private/tc.h>
  18. #include <netlink/netlink.h>
  19. #include <netlink/cache.h>
  20. #include <netlink/utils.h>
  21. #include <netlink-private/route/tc-api.h>
  22. #include <netlink/route/qdisc.h>
  23. #include <netlink/route/class.h>
  24. #include <netlink/route/link.h>
  25. #include <netlink/route/qdisc/tbf.h>
  26. /** @cond SKIP */
  27. #define TBF_ATTR_LIMIT 0x01
  28. #define TBF_ATTR_RATE 0x02
  29. #define TBF_ATTR_PEAKRATE 0x10
  30. /** @endcond */
  31. static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = {
  32. [TCA_TBF_PARMS] = { .minlen = sizeof(struct tc_tbf_qopt) },
  33. };
  34. static int tbf_msg_parser(struct rtnl_tc *tc, void *data)
  35. {
  36. struct nlattr *tb[TCA_TBF_MAX + 1];
  37. struct rtnl_tbf *tbf = data;
  38. int err;
  39. if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0)
  40. return err;
  41. if (tb[TCA_TBF_PARMS]) {
  42. struct tc_tbf_qopt opts;
  43. int bufsize;
  44. nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts));
  45. tbf->qt_limit = opts.limit;
  46. rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate);
  47. tbf->qt_rate_txtime = opts.buffer;
  48. bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
  49. opts.rate.rate);
  50. tbf->qt_rate_bucket = bufsize;
  51. rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate);
  52. tbf->qt_peakrate_txtime = opts.mtu;
  53. bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu),
  54. opts.peakrate.rate);
  55. tbf->qt_peakrate_bucket = bufsize;
  56. rtnl_tc_set_mpu(tc, tbf->qt_rate.rs_mpu);
  57. rtnl_tc_set_overhead(tc, tbf->qt_rate.rs_overhead);
  58. tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_RATE | TBF_ATTR_PEAKRATE);
  59. }
  60. return 0;
  61. }
  62. static void tbf_dump_line(struct rtnl_tc *tc, void *data,
  63. struct nl_dump_params *p)
  64. {
  65. double r, rbit, lim;
  66. char *ru, *rubit, *limu;
  67. struct rtnl_tbf *tbf = data;
  68. if (!tbf)
  69. return;
  70. r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru);
  71. rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit);
  72. lim = nl_cancel_down_bytes(tbf->qt_limit, &limu);
  73. nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s",
  74. r, ru, rbit, rubit, lim, limu);
  75. }
  76. static void tbf_dump_details(struct rtnl_tc *tc, void *data,
  77. struct nl_dump_params *p)
  78. {
  79. struct rtnl_tbf *tbf = data;
  80. if (!tbf)
  81. return;
  82. if (1) {
  83. char *bu, *cu;
  84. double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu);
  85. double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log,
  86. &cu);
  87. nl_dump(p, "rate-bucket-size %1.f%s "
  88. "rate-cell-size %.1f%s\n",
  89. bs, bu, cl, cu);
  90. }
  91. if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
  92. char *pru, *prbu, *bsu, *clu;
  93. double pr, prb, bs, cl;
  94. pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru);
  95. prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu);
  96. bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu);
  97. cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log,
  98. &clu);
  99. nl_dump_line(p, " peak-rate %.2f%s/s (%.0f%s) "
  100. "bucket-size %.1f%s cell-size %.1f%s"
  101. "latency %.1f%s",
  102. pr, pru, prb, prbu, bs, bsu, cl, clu);
  103. }
  104. }
  105. static int tbf_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
  106. {
  107. uint32_t rtab[RTNL_TC_RTABLE_SIZE], ptab[RTNL_TC_RTABLE_SIZE];
  108. struct tc_tbf_qopt opts;
  109. struct rtnl_tbf *tbf = data;
  110. int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
  111. if ((tbf->qt_mask & required) != required)
  112. return -NLE_MISSING_ATTR;
  113. memset(&opts, 0, sizeof(opts));
  114. opts.limit = tbf->qt_limit;
  115. opts.buffer = tbf->qt_rate_txtime;
  116. rtnl_tc_build_rate_table(tc, &tbf->qt_rate, rtab);
  117. rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate);
  118. if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
  119. opts.mtu = tbf->qt_peakrate_txtime;
  120. rtnl_tc_build_rate_table(tc, &tbf->qt_peakrate, ptab);
  121. rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate);
  122. }
  123. NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opts), &opts);
  124. NLA_PUT(msg, TCA_TBF_RTAB, sizeof(rtab), rtab);
  125. if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
  126. NLA_PUT(msg, TCA_TBF_PTAB, sizeof(ptab), ptab);
  127. return 0;
  128. nla_put_failure:
  129. return -NLE_MSGSIZE;
  130. }
  131. /**
  132. * @name Attribute Access
  133. * @{
  134. */
  135. /**
  136. * Set limit of TBF qdisc.
  137. * @arg qdisc TBF qdisc to be modified.
  138. * @arg limit New limit in bytes.
  139. * @return 0 on success or a negative error code.
  140. */
  141. void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit)
  142. {
  143. struct rtnl_tbf *tbf;
  144. if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
  145. BUG();
  146. tbf->qt_limit = limit;
  147. tbf->qt_mask |= TBF_ATTR_LIMIT;
  148. }
  149. static inline double calc_limit(struct rtnl_ratespec *spec, int latency,
  150. int bucket)
  151. {
  152. double limit;
  153. limit = (double) spec->rs_rate * ((double) latency / 1000000.);
  154. limit += bucket;
  155. return limit;
  156. }
  157. /**
  158. * Set limit of TBF qdisc by latency.
  159. * @arg qdisc TBF qdisc to be modified.
  160. * @arg latency Latency in micro seconds.
  161. *
  162. * Calculates and sets the limit based on the desired latency and the
  163. * configured rate and peak rate. In order for this operation to succeed,
  164. * the rate and if required the peak rate must have been set in advance.
  165. *
  166. * @f[
  167. * limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n
  168. * @f]
  169. * @f[
  170. * limit = min(limit_{rate},limit_{peak})
  171. * @f]
  172. *
  173. * @return 0 on success or a negative error code.
  174. */
  175. int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency)
  176. {
  177. struct rtnl_tbf *tbf;
  178. double limit, limit2;
  179. if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
  180. BUG();
  181. if (!(tbf->qt_mask & TBF_ATTR_RATE))
  182. return -NLE_MISSING_ATTR;
  183. limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket);
  184. if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
  185. limit2 = calc_limit(&tbf->qt_peakrate, latency,
  186. tbf->qt_peakrate_bucket);
  187. if (limit2 < limit)
  188. limit = limit2;
  189. }
  190. rtnl_qdisc_tbf_set_limit(qdisc, (int) limit);
  191. return 0;
  192. }
  193. /**
  194. * Get limit of TBF qdisc.
  195. * @arg qdisc TBF qdisc.
  196. * @return Limit in bytes or a negative error code.
  197. */
  198. int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc)
  199. {
  200. struct rtnl_tbf *tbf;
  201. if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
  202. BUG();
  203. if (tbf->qt_mask & TBF_ATTR_LIMIT)
  204. return tbf->qt_limit;
  205. else
  206. return -NLE_NOATTR;
  207. }
  208. static inline int calc_cell_log(int cell, int bucket)
  209. {
  210. cell = rtnl_tc_calc_cell_log(cell);
  211. return cell;
  212. }
  213. /**
  214. * Set rate of TBF qdisc.
  215. * @arg qdisc TBF qdisc to be modified.
  216. * @arg rate New rate in bytes per second.
  217. * @arg bucket Size of bucket in bytes.
  218. * @arg cell Size of a rate cell or 0 to get default value.
  219. * @return 0 on success or a negative error code.
  220. */
  221. void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
  222. int cell)
  223. {
  224. struct rtnl_tbf *tbf;
  225. int cell_log;
  226. if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
  227. BUG();
  228. if (!cell)
  229. cell_log = UINT8_MAX;
  230. else
  231. cell_log = rtnl_tc_calc_cell_log(cell);
  232. tbf->qt_rate.rs_rate = rate;
  233. tbf->qt_rate_bucket = bucket;
  234. tbf->qt_rate.rs_cell_log = cell_log;
  235. tbf->qt_rate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate));
  236. tbf->qt_mask |= TBF_ATTR_RATE;
  237. }
  238. /**
  239. * Get rate of TBF qdisc.
  240. * @arg qdisc TBF qdisc.
  241. * @return Rate in bytes per seconds or a negative error code.
  242. */
  243. int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc)
  244. {
  245. struct rtnl_tbf *tbf;
  246. if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
  247. BUG();
  248. if (tbf->qt_mask & TBF_ATTR_RATE)
  249. return tbf->qt_rate.rs_rate;
  250. else
  251. return -1;
  252. }
  253. /**
  254. * Get rate bucket size of TBF qdisc.
  255. * @arg qdisc TBF qdisc.
  256. * @return Size of rate bucket or a negative error code.
  257. */
  258. int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc)
  259. {
  260. struct rtnl_tbf *tbf;
  261. if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
  262. BUG();
  263. if (tbf->qt_mask & TBF_ATTR_RATE)
  264. return tbf->qt_rate_bucket;
  265. else
  266. return -1;
  267. }
  268. /**
  269. * Get rate cell size of TBF qdisc.
  270. * @arg qdisc TBF qdisc.
  271. * @return Size of rate cell in bytes or a negative error code.
  272. */
  273. int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc)
  274. {
  275. struct rtnl_tbf *tbf;
  276. if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
  277. BUG();
  278. if (tbf->qt_mask & TBF_ATTR_RATE)
  279. return (1 << tbf->qt_rate.rs_cell_log);
  280. else
  281. return -1;
  282. }
  283. /**
  284. * Set peak rate of TBF qdisc.
  285. * @arg qdisc TBF qdisc to be modified.
  286. * @arg rate New peak rate in bytes per second.
  287. * @arg bucket Size of peakrate bucket.
  288. * @arg cell Size of a peakrate cell or 0 to get default value.
  289. * @return 0 on success or a negative error code.
  290. */
  291. int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
  292. int cell)
  293. {
  294. struct rtnl_tbf *tbf;
  295. int cell_log;
  296. if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
  297. BUG();
  298. cell_log = calc_cell_log(cell, bucket);
  299. if (cell_log < 0)
  300. return cell_log;
  301. tbf->qt_peakrate.rs_rate = rate;
  302. tbf->qt_peakrate_bucket = bucket;
  303. tbf->qt_peakrate.rs_cell_log = cell_log;
  304. tbf->qt_peakrate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate));
  305. tbf->qt_mask |= TBF_ATTR_PEAKRATE;
  306. return 0;
  307. }
  308. /**
  309. * Get peak rate of TBF qdisc.
  310. * @arg qdisc TBF qdisc.
  311. * @return Peak rate in bytes per seconds or a negative error code.
  312. */
  313. int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc)
  314. {
  315. struct rtnl_tbf *tbf;
  316. if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
  317. BUG();
  318. if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
  319. return tbf->qt_peakrate.rs_rate;
  320. else
  321. return -1;
  322. }
  323. /**
  324. * Get peak rate bucket size of TBF qdisc.
  325. * @arg qdisc TBF qdisc.
  326. * @return Size of peak rate bucket or a negative error code.
  327. */
  328. int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc)
  329. {
  330. struct rtnl_tbf *tbf;
  331. if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
  332. BUG();
  333. if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
  334. return tbf->qt_peakrate_bucket;
  335. else
  336. return -1;
  337. }
  338. /**
  339. * Get peak rate cell size of TBF qdisc.
  340. * @arg qdisc TBF qdisc.
  341. * @return Size of peak rate cell in bytes or a negative error code.
  342. */
  343. int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc)
  344. {
  345. struct rtnl_tbf *tbf;
  346. if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
  347. BUG();
  348. if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
  349. return (1 << tbf->qt_peakrate.rs_cell_log);
  350. else
  351. return -1;
  352. }
  353. /** @} */
  354. static struct rtnl_tc_ops tbf_tc_ops = {
  355. .to_kind = "tbf",
  356. .to_type = RTNL_TC_TYPE_QDISC,
  357. .to_size = sizeof(struct rtnl_tbf),
  358. .to_msg_parser = tbf_msg_parser,
  359. .to_dump = {
  360. [NL_DUMP_LINE] = tbf_dump_line,
  361. [NL_DUMP_DETAILS] = tbf_dump_details,
  362. },
  363. .to_msg_fill = tbf_msg_fill,
  364. };
  365. static void __init tbf_init(void)
  366. {
  367. rtnl_tc_register(&tbf_tc_ops);
  368. }
  369. static void __exit tbf_exit(void)
  370. {
  371. rtnl_tc_unregister(&tbf_tc_ops);
  372. }
  373. /** @} */