tbf.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. /*
  2. * lib/route/sch/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-2006 Thomas Graf <tgraf@suug.ch>
  10. */
  11. /**
  12. * @ingroup qdisc_api
  13. * @defgroup tbf Token Bucket Filter (TBF)
  14. * @{
  15. */
  16. #include <netlink-local.h>
  17. #include <netlink-tc.h>
  18. #include <netlink/netlink.h>
  19. #include <netlink/cache.h>
  20. #include <netlink/utils.h>
  21. #include <netlink/route/tc.h>
  22. #include <netlink/route/qdisc.h>
  23. #include <netlink/route/qdisc-modules.h>
  24. #include <netlink/route/class.h>
  25. #include <netlink/route/class-modules.h>
  26. #include <netlink/route/link.h>
  27. #include <netlink/route/sch/tbf.h>
  28. /** @cond SKIP */
  29. #define TBF_ATTR_LIMIT 0x01
  30. #define TBF_ATTR_RATE 0x02
  31. #define TBF_ATTR_PEAKRATE 0x10
  32. #define TBF_ATTR_MPU 0x80
  33. /** @endcond */
  34. static inline struct rtnl_tbf *tbf_qdisc(struct rtnl_qdisc *qdisc)
  35. {
  36. return (struct rtnl_tbf *) qdisc->q_subdata;
  37. }
  38. static inline struct rtnl_tbf *tbf_alloc(struct rtnl_qdisc *qdisc)
  39. {
  40. if (!qdisc->q_subdata)
  41. qdisc->q_subdata = calloc(1, sizeof(struct rtnl_tbf));
  42. return tbf_qdisc(qdisc);
  43. }
  44. static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = {
  45. [TCA_TBF_PARMS] = { .minlen = sizeof(struct tc_tbf_qopt) },
  46. };
  47. static int tbf_msg_parser(struct rtnl_qdisc *q)
  48. {
  49. int err;
  50. struct nlattr *tb[TCA_TBF_MAX + 1];
  51. struct rtnl_tbf *tbf;
  52. err = tca_parse(tb, TCA_TBF_MAX, (struct rtnl_tca *) q, tbf_policy);
  53. if (err < 0)
  54. return err;
  55. tbf = tbf_qdisc(q);
  56. if (!tbf)
  57. return nl_errno(ENOMEM);
  58. if (tb[TCA_TBF_PARMS]) {
  59. struct tc_tbf_qopt opts;
  60. int bufsize;
  61. nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts));
  62. tbf->qt_limit = opts.limit;
  63. tbf->qt_mpu = opts.rate.mpu;
  64. rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate);
  65. tbf->qt_rate_txtime = opts.buffer;
  66. bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
  67. opts.rate.rate);
  68. tbf->qt_rate_bucket = bufsize;
  69. rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate);
  70. tbf->qt_peakrate_txtime = opts.mtu;
  71. bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu),
  72. opts.peakrate.rate);
  73. tbf->qt_peakrate_bucket = bufsize;
  74. tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_MPU | TBF_ATTR_RATE |
  75. TBF_ATTR_PEAKRATE);
  76. }
  77. return 0;
  78. }
  79. static int tbf_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
  80. int line)
  81. {
  82. double r, rbit, lim;
  83. char *ru, *rubit, *limu;
  84. struct rtnl_tbf *tbf = tbf_qdisc(qdisc);
  85. if (!tbf)
  86. goto ignore;
  87. r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru);
  88. rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit);
  89. lim = nl_cancel_down_bytes(tbf->qt_limit, &limu);
  90. dp_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s",
  91. r, ru, rbit, rubit, lim, limu);
  92. ignore:
  93. return line;
  94. }
  95. static int tbf_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
  96. int line)
  97. {
  98. struct rtnl_tbf *tbf = tbf_qdisc(qdisc);
  99. if (!tbf)
  100. goto ignore;
  101. if (1) {
  102. char *bu, *cu;
  103. double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu);
  104. double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log,
  105. &cu);
  106. dp_dump(p, "mpu %u rate-bucket-size %1.f%s "
  107. "rate-cell-size %.1f%s\n",
  108. tbf->qt_mpu, bs, bu, cl, cu);
  109. }
  110. if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
  111. char *pru, *prbu, *bsu, *clu;
  112. double pr, prb, bs, cl;
  113. pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru);
  114. prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu);
  115. bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu);
  116. cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log,
  117. &clu);
  118. dp_dump_line(p, line++, " peak-rate %.2f%s/s (%.0f%s) "
  119. "bucket-size %.1f%s cell-size %.1f%s",
  120. "latency %.1f%s",
  121. pr, pru, prb, prbu, bs, bsu, cl, clu);
  122. }
  123. ignore:
  124. return line;
  125. }
  126. static struct nl_msg *tbf_get_opts(struct rtnl_qdisc *qdisc)
  127. {
  128. struct tc_tbf_qopt opts;
  129. struct rtnl_tbf *tbf;
  130. struct nl_msg *msg;
  131. uint32_t rtab[RTNL_TC_RTABLE_SIZE];
  132. uint32_t ptab[RTNL_TC_RTABLE_SIZE];
  133. int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
  134. memset(&opts, 0, sizeof(opts));
  135. tbf = tbf_qdisc(qdisc);
  136. if (!tbf)
  137. return NULL;
  138. if (!(tbf->qt_mask & required) != required)
  139. return NULL;
  140. opts.limit = tbf->qt_limit;
  141. opts.buffer = tbf->qt_rate_txtime;
  142. tbf->qt_rate.rs_mpu = tbf->qt_mpu;
  143. rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate);
  144. rtnl_tc_build_rate_table(rtab, tbf->qt_mpu & 0xff, tbf->qt_mpu >> 8,
  145. 1 << tbf->qt_rate.rs_cell_log,
  146. tbf->qt_rate.rs_rate);
  147. if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
  148. opts.mtu = tbf->qt_peakrate_txtime;
  149. tbf->qt_peakrate.rs_mpu = tbf->qt_mpu;
  150. rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate);
  151. rtnl_tc_build_rate_table(ptab, tbf->qt_mpu & 0xff,
  152. tbf->qt_mpu >> 8,
  153. 1 << tbf->qt_peakrate.rs_cell_log,
  154. tbf->qt_peakrate.rs_rate);
  155. }
  156. msg = nlmsg_alloc();
  157. if (!msg)
  158. goto nla_put_failure;
  159. NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opts), &opts);
  160. NLA_PUT(msg, TCA_TBF_RTAB, sizeof(rtab), rtab);
  161. if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
  162. NLA_PUT(msg, TCA_TBF_PTAB, sizeof(ptab), ptab);
  163. return msg;
  164. nla_put_failure:
  165. nlmsg_free(msg);
  166. return NULL;
  167. }
  168. /**
  169. * @name Attribute Access
  170. * @{
  171. */
  172. /**
  173. * Set limit of TBF qdisc.
  174. * @arg qdisc TBF qdisc to be modified.
  175. * @arg limit New limit in bytes.
  176. * @return 0 on success or a negative error code.
  177. */
  178. int rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit)
  179. {
  180. struct rtnl_tbf *tbf;
  181. tbf = tbf_alloc(qdisc);
  182. if (!tbf)
  183. return nl_errno(ENOMEM);
  184. tbf->qt_limit = limit;
  185. tbf->qt_mask |= TBF_ATTR_LIMIT;
  186. return 0;
  187. }
  188. static inline double calc_limit(struct rtnl_ratespec *spec, int latency,
  189. int bucket)
  190. {
  191. double limit;
  192. limit = (double) spec->rs_rate * ((double) latency / 1000000.);
  193. limit += bucket;
  194. return limit;
  195. }
  196. /**
  197. * Set limit of TBF qdisc by latency.
  198. * @arg qdisc TBF qdisc to be modified.
  199. * @arg latency Latency in micro seconds.
  200. *
  201. * Calculates and sets the limit based on the desired latency and the
  202. * configured rate and peak rate. In order for this operation to succeed,
  203. * the rate and if required the peak rate must have been set in advance.
  204. *
  205. * @f[
  206. * limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n
  207. * @f]
  208. * @f[
  209. * limit = min(limit_{rate},limit_{peak})
  210. * @f]
  211. *
  212. * @return 0 on success or a negative error code.
  213. */
  214. int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency)
  215. {
  216. struct rtnl_tbf *tbf;
  217. double limit, limit2;
  218. tbf = tbf_alloc(qdisc);
  219. if (!tbf)
  220. return nl_errno(ENOMEM);
  221. if (!(tbf->qt_mask & TBF_ATTR_RATE))
  222. return nl_error(EINVAL, "The rate must be specified before "
  223. "limit can be calculated based on latency.");
  224. 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);
  228. if (limit2 < limit)
  229. limit = limit2;
  230. }
  231. return rtnl_qdisc_tbf_set_limit(qdisc, (int) limit);
  232. }
  233. /**
  234. * Get limit of TBF qdisc.
  235. * @arg qdisc TBF qdisc.
  236. * @return Limit in bytes or a negative error code.
  237. */
  238. int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc)
  239. {
  240. struct rtnl_tbf *tbf;
  241. tbf = tbf_qdisc(qdisc);
  242. if (tbf && (tbf->qt_mask & TBF_ATTR_LIMIT))
  243. return tbf->qt_limit;
  244. return
  245. nl_errno(ENOENT);
  246. }
  247. /**
  248. * Set MPU of TBF qdisc.
  249. * @arg qdisc TBF qdisc to be modified.
  250. * @arg mpu New MPU in bytes.
  251. * @return 0 on success or a negative error code.
  252. */
  253. int rtnl_qdisc_tbf_set_mpu(struct rtnl_qdisc *qdisc, int mpu)
  254. {
  255. struct rtnl_tbf *tbf;
  256. tbf = tbf_alloc(qdisc);
  257. if (!tbf)
  258. return nl_errno(ENOMEM);
  259. tbf->qt_mpu = mpu;
  260. tbf->qt_mask |= TBF_ATTR_MPU;
  261. return 0;
  262. }
  263. /**
  264. * Get MPU of TBF qdisc.
  265. * @arg qdisc TBF qdisc.
  266. * @return MPU in bytes or a negative error code.
  267. */
  268. int rtnl_qdisc_tbf_get_mpu(struct rtnl_qdisc *qdisc)
  269. {
  270. struct rtnl_tbf *tbf;
  271. tbf = tbf_qdisc(qdisc);
  272. if (tbf && (tbf->qt_mask & TBF_ATTR_MPU))
  273. return tbf->qt_mpu;
  274. return
  275. nl_errno(ENOENT);
  276. }
  277. static inline int calc_cell_log(int cell, int bucket)
  278. {
  279. if (cell > 0)
  280. cell = rtnl_tc_calc_cell_log(cell);
  281. else {
  282. cell = 0;
  283. if (!bucket)
  284. bucket = 2047; /* defaults to cell_log=3 */
  285. while ((bucket >> cell) > 255)
  286. cell++;
  287. }
  288. return cell;
  289. }
  290. /**
  291. * Set rate of TBF qdisc.
  292. * @arg qdisc TBF qdisc to be modified.
  293. * @arg rate New rate in bytes per second.
  294. * @arg bucket Size of bucket in bytes.
  295. * @arg cell Size of a rate cell or 0 to get default value.
  296. * @return 0 on success or a negative error code.
  297. */
  298. int rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
  299. int cell)
  300. {
  301. struct rtnl_tbf *tbf;
  302. int cell_log;
  303. tbf = tbf_alloc(qdisc);
  304. if (!tbf)
  305. return nl_errno(ENOMEM);
  306. cell_log = calc_cell_log(cell, bucket);
  307. if (cell_log < 0)
  308. return cell_log;
  309. tbf->qt_rate.rs_rate = rate;
  310. tbf->qt_rate_bucket = bucket;
  311. tbf->qt_rate.rs_cell_log = cell_log;
  312. tbf->qt_rate_txtime = rtnl_tc_calc_txtime(bucket, rate);
  313. tbf->qt_mask |= TBF_ATTR_RATE;
  314. return 0;
  315. }
  316. /**
  317. * Get rate of TBF qdisc.
  318. * @arg qdisc TBF qdisc.
  319. * @return Rate in bytes per seconds or a negative error code.
  320. */
  321. int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc)
  322. {
  323. struct rtnl_tbf *tbf;
  324. tbf = tbf_qdisc(qdisc);
  325. if (tbf && (tbf->qt_mask & TBF_ATTR_RATE))
  326. return tbf->qt_rate.rs_rate;
  327. else
  328. return -1;
  329. }
  330. /**
  331. * Get rate bucket size of TBF qdisc.
  332. * @arg qdisc TBF qdisc.
  333. * @return Size of rate bucket or a negative error code.
  334. */
  335. int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc)
  336. {
  337. struct rtnl_tbf *tbf;
  338. tbf = tbf_qdisc(qdisc);
  339. if (tbf && (tbf->qt_mask & TBF_ATTR_RATE))
  340. return tbf->qt_rate_bucket;
  341. else
  342. return -1;
  343. }
  344. /**
  345. * Get rate cell size of TBF qdisc.
  346. * @arg qdisc TBF qdisc.
  347. * @return Size of rate cell in bytes or a negative error code.
  348. */
  349. int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc)
  350. {
  351. struct rtnl_tbf *tbf;
  352. tbf = tbf_qdisc(qdisc);
  353. if (tbf && (tbf->qt_mask & TBF_ATTR_RATE))
  354. return (1 << tbf->qt_rate.rs_cell_log);
  355. else
  356. return -1;
  357. }
  358. /**
  359. * Set peak rate of TBF qdisc.
  360. * @arg qdisc TBF qdisc to be modified.
  361. * @arg rate New peak rate in bytes per second.
  362. * @arg bucket Size of peakrate bucket.
  363. * @arg cell Size of a peakrate cell or 0 to get default value.
  364. * @return 0 on success or a negative error code.
  365. */
  366. int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
  367. int cell)
  368. {
  369. struct rtnl_tbf *tbf;
  370. int cell_log;
  371. tbf = tbf_alloc(qdisc);
  372. if (!tbf)
  373. return nl_errno(ENOMEM);
  374. cell_log = calc_cell_log(cell, bucket);
  375. if (cell_log < 0)
  376. return cell_log;
  377. tbf->qt_peakrate.rs_rate = rate;
  378. tbf->qt_peakrate_bucket = bucket;
  379. tbf->qt_peakrate.rs_cell_log = cell_log;
  380. tbf->qt_peakrate_txtime = rtnl_tc_calc_txtime(bucket, rate);
  381. tbf->qt_mask |= TBF_ATTR_PEAKRATE;
  382. return 0;
  383. }
  384. /**
  385. * Get peak rate of TBF qdisc.
  386. * @arg qdisc TBF qdisc.
  387. * @return Peak rate in bytes per seconds or a negative error code.
  388. */
  389. int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc)
  390. {
  391. struct rtnl_tbf *tbf;
  392. tbf = tbf_qdisc(qdisc);
  393. if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE))
  394. return tbf->qt_peakrate.rs_rate;
  395. else
  396. return -1;
  397. }
  398. /**
  399. * Get peak rate bucket size of TBF qdisc.
  400. * @arg qdisc TBF qdisc.
  401. * @return Size of peak rate bucket or a negative error code.
  402. */
  403. int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc)
  404. {
  405. struct rtnl_tbf *tbf;
  406. tbf = tbf_qdisc(qdisc);
  407. if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE))
  408. return tbf->qt_peakrate_bucket;
  409. else
  410. return -1;
  411. }
  412. /**
  413. * Get peak rate cell size of TBF qdisc.
  414. * @arg qdisc TBF qdisc.
  415. * @return Size of peak rate cell in bytes or a negative error code.
  416. */
  417. int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc)
  418. {
  419. struct rtnl_tbf *tbf;
  420. tbf = tbf_qdisc(qdisc);
  421. if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE))
  422. return (1 << tbf->qt_peakrate.rs_cell_log);
  423. else
  424. return -1;
  425. }
  426. /** @} */
  427. static struct rtnl_qdisc_ops tbf_qdisc_ops = {
  428. .qo_kind = "tbf",
  429. .qo_msg_parser = tbf_msg_parser,
  430. .qo_dump[NL_DUMP_BRIEF] = tbf_dump_brief,
  431. .qo_dump[NL_DUMP_FULL] = tbf_dump_full,
  432. .qo_get_opts = tbf_get_opts,
  433. };
  434. static void __init tbf_init(void)
  435. {
  436. rtnl_qdisc_register(&tbf_qdisc_ops);
  437. }
  438. static void __exit tbf_exit(void)
  439. {
  440. rtnl_qdisc_unregister(&tbf_qdisc_ops);
  441. }
  442. /** @} */